]> git.saurik.com Git - apple/configd.git/commitdiff
configd-453.16.tar.gz mac-os-x-108 mac-os-x-1081 v453.16
authorApple <opensource@apple.com>
Tue, 24 Jul 2012 15:52:23 +0000 (15:52 +0000)
committerApple <opensource@apple.com>
Tue, 24 Jul 2012 15:52:23 +0000 (15:52 +0000)
178 files changed:
Makefile
Plugins/IPMonitor/Info.plist
Plugins/IPMonitor/Makefile
Plugins/IPMonitor/dns-configuration.c
Plugins/IPMonitor/dns-configuration.h
Plugins/IPMonitor/ip_plugin.c
Plugins/IPMonitor/proxy-configuration.c
Plugins/IPMonitor/proxy-configuration.h
Plugins/IPMonitor/set-hostname.c
Plugins/IPMonitor/set-hostname.h
Plugins/IPMonitor/smb-configuration.c
Plugins/IPMonitor/smb-configuration.h
Plugins/IPMonitor/test_ipv4_routelist_reference.txt
Plugins/InterfaceNamer/Info.plist
Plugins/InterfaceNamer/ifnamer.c
Plugins/KernelEventMonitor/Info.plist
Plugins/KernelEventMonitor/ev_dlil.c
Plugins/KernelEventMonitor/ev_dlil.h
Plugins/KernelEventMonitor/ev_ipv4.c
Plugins/KernelEventMonitor/ev_ipv4.h
Plugins/KernelEventMonitor/ev_ipv6.c
Plugins/KernelEventMonitor/ev_ipv6.h
Plugins/KernelEventMonitor/eventmon.c
Plugins/KernelEventMonitor/eventmon.h
Plugins/LinkConfiguration/Info.plist
Plugins/LinkConfiguration/linkconfig.c
Plugins/Logger/Info-Embedded.plist
Plugins/Logger/Info.plist
Plugins/Logger/logger.c
Plugins/NetworkIdentification/Info.plist [deleted file]
Plugins/NetworkIdentification/Makefile [deleted file]
Plugins/NetworkIdentification/NetworkIdentification.c [deleted file]
Plugins/PreferencesMonitor/Info.plist
Plugins/PreferencesMonitor/prefsmon.c
Plugins/SCNetworkReachability/Info.plist [new file with mode: 0644]
Plugins/SCNetworkReachability/Makefile [new file with mode: 0644]
Plugins/common/cache.c
SCMonitor/Info.plist
SCMonitor/monitor.c
SystemConfiguration.fproj/BridgeConfiguration.c
SystemConfiguration.fproj/CaptiveNetwork.c
SystemConfiguration.fproj/CaptiveNetwork.h
SystemConfiguration.fproj/DHCP.c
SystemConfiguration.fproj/English.lproj/NetworkInterface.strings
SystemConfiguration.fproj/Info-Embedded.plist
SystemConfiguration.fproj/Info.plist
SystemConfiguration.fproj/SCD.c
SystemConfiguration.fproj/SCD.h [new file with mode: 0644]
SystemConfiguration.fproj/SCDAdd.c
SystemConfiguration.fproj/SCDConsoleUser.c
SystemConfiguration.fproj/SCDGet.c
SystemConfiguration.fproj/SCDHostName.c
SystemConfiguration.fproj/SCDList.c
SystemConfiguration.fproj/SCDLock.c [deleted file]
SystemConfiguration.fproj/SCDNotifierAdd.c
SystemConfiguration.fproj/SCDNotifierCancel.c
SystemConfiguration.fproj/SCDNotifierGetChanges.c
SystemConfiguration.fproj/SCDNotifierInformViaCallback.c
SystemConfiguration.fproj/SCDNotifierInformViaFD.c
SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c [deleted file]
SystemConfiguration.fproj/SCDNotifierInformViaSignal.c
SystemConfiguration.fproj/SCDNotifierRemove.c
SystemConfiguration.fproj/SCDNotifierSetKeys.c
SystemConfiguration.fproj/SCDNotifierWait.c
SystemConfiguration.fproj/SCDNotify.c
SystemConfiguration.fproj/SCDOpen.c
SystemConfiguration.fproj/SCDPrivate.c
SystemConfiguration.fproj/SCDRemove.c
SystemConfiguration.fproj/SCDSet.c
SystemConfiguration.fproj/SCDSnapshot.c
SystemConfiguration.fproj/SCDTouch.c [deleted file]
SystemConfiguration.fproj/SCDUnlock.c [deleted file]
SystemConfiguration.fproj/SCDynamicStoreCopyDHCPInfo.h
SystemConfiguration.fproj/SCDynamicStoreInternal.h
SystemConfiguration.fproj/SCDynamicStorePrivate.h
SystemConfiguration.fproj/SCLocation.c
SystemConfiguration.fproj/SCNetworkConfigurationInternal.c
SystemConfiguration.fproj/SCNetworkConfigurationInternal.h
SystemConfiguration.fproj/SCNetworkConfigurationPrivate.h
SystemConfiguration.fproj/SCNetworkConnection.c
SystemConfiguration.fproj/SCNetworkConnectionPrivate.c
SystemConfiguration.fproj/SCNetworkConnectionPrivate.h
SystemConfiguration.fproj/SCNetworkInterface.c
SystemConfiguration.fproj/SCNetworkReachability.c
SystemConfiguration.fproj/SCNetworkReachabilityInternal.h [new file with mode: 0644]
SystemConfiguration.fproj/SCNetworkService.c
SystemConfiguration.fproj/SCNetworkSet.c
SystemConfiguration.fproj/SCNetworkSignature.c
SystemConfiguration.fproj/SCNetworkSignature.h
SystemConfiguration.fproj/SCP.c
SystemConfiguration.fproj/SCPOpen.c
SystemConfiguration.fproj/SCPPath.c
SystemConfiguration.fproj/SCPreferencesInternal.h
SystemConfiguration.fproj/SCPreferencesPrivate.h
SystemConfiguration.fproj/SCPrivate.h
SystemConfiguration.fproj/SCProxies.c
SystemConfiguration.fproj/SCSchemaDefinitions.c
SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h
SystemConfiguration.fproj/VLANConfiguration.c
SystemConfiguration.fproj/config.defs
SystemConfiguration.fproj/dy_framework.c
SystemConfiguration.fproj/dy_framework.h
SystemConfiguration.fproj/genSCPreferences.c
SystemConfiguration.fproj/helper/SCHelper_client.c
SystemConfiguration.fproj/helper/SCHelper_client.h
SystemConfiguration.fproj/helper/SCHelper_server.c
SystemConfiguration.fproj/helper/helper.defs
SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_client.c [new file with mode: 0644]
SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_server.c [new file with mode: 0644]
SystemConfiguration.fproj/reachability/client.c [new file with mode: 0644]
SystemConfiguration.fproj/reachability/rb.c [new file with mode: 0644]
SystemConfiguration.fproj/reachability/rb.h [new file with mode: 0644]
SystemConfiguration.fproj/reachability/server.c [new file with mode: 0644]
configd.tproj/_SCD.c
configd.tproj/_SCD.h
configd.tproj/_configadd.c
configd.tproj/_configclose.c
configd.tproj/_configget.c
configd.tproj/_configlist.c
configd.tproj/_configlock.c [deleted file]
configd.tproj/_confignotify.c
configd.tproj/_configopen.c
configd.tproj/_configremove.c
configd.tproj/_configset.c
configd.tproj/_configtouch.c [deleted file]
configd.tproj/_configunlock.c
configd.tproj/_notifyadd.c
configd.tproj/_notifychanges.c
configd.tproj/_notifyremove.c
configd.tproj/_notifyviafd.c
configd.tproj/_notifyviaport.c
configd.tproj/_notifyviasignal.c
configd.tproj/_snapshot.c
configd.tproj/com.apple.configd.plist
configd.tproj/configd.h
configd.tproj/configd.m
configd.tproj/configd_server.c
configd.tproj/configd_server.h
configd.tproj/entitlements.plist
configd.tproj/pattern.c
configd.tproj/plugin_support.c
configd.tproj/session.c
configd.tproj/session.h
configd.xcodeproj/project.pbxproj
dnsinfo/dnsinfo.h
dnsinfo/dnsinfo_copy.c
dnsinfo/dnsinfo_create.c
dnsinfo/dnsinfo_create.h
dnsinfo/dnsinfo_flatfile.c
dnsinfo/dnsinfo_server.c
dnsinfo/dnsinfo_server.h
dnsinfo/shared_dns_info.defs
get-mobility-info
nwi/network_information.c [new file with mode: 0644]
nwi/network_information.h [new file with mode: 0644]
nwi/network_information_priv.c [new file with mode: 0644]
nwi/network_information_priv.h [new file with mode: 0644]
scselect.tproj/scselect.c
scutil.tproj/cache.c
scutil.tproj/cache.h
scutil.tproj/commands.c
scutil.tproj/dictionary.c
scutil.tproj/nc.c
scutil.tproj/nc.h
scutil.tproj/net.c
scutil.tproj/net.h
scutil.tproj/net_interface.c
scutil.tproj/net_interface.h
scutil.tproj/net_protocol.c
scutil.tproj/net_protocol.h
scutil.tproj/notifications.c
scutil.tproj/notifications.h
scutil.tproj/prefs.c
scutil.tproj/scutil.c
scutil.tproj/session.c
scutil.tproj/session.h
scutil.tproj/tests.c
scutil.tproj/tests.h

index b3d4dc2949c69cb50c152c3692340fc5f748c7b1..af81588b7b52bc164ebd8520d91e9bff4b43f65a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -12,33 +12,25 @@ all :
          -noinstallsrc -noinstallhdrs -noverify -nosum         \
          -arch i386 -arch x86_64 -arch ppc                     \
          -target All                                           \
-         -project configd                                      \
+         -project ${PROJECT}-${VERSION}                        \
          -configuration Debug                                  \
          -release $(shell cat /usr/share/buildit/.releaseName) \
 
 #----------------------------------------------------------------------
 #
-# Build for SnowLeopard, SUSnowXXX, ...
-#
-# Note: assumes that the "pppcontroller_sendmsg" routine has been defined
-#       in pppcontroller.defs.
+# Darwin build
 #
 #----------------------------------------------------------------------
 
-SNOW_CFLAGS += -D__MAC_10_7=1060
-SNOW_CFLAGS += -D__AVAILABILITY_INTERNAL__MAC_10_7=__AVAILABILITY_INTERNAL__MAC_10_6
-SNOW_CFLAGS += -D__AVAILABILITY_INTERNAL__MAC_10_5_DEP__MAC_10_7=__AVAILABILITY_INTERNAL__MAC_10_5
-#SNOW_CFLAGS += -DHAVE_PPPCONTROLLER_SENDMSG=YES
-
-snow :
+darwin :
        /usr/local/bin/buildit .                                \
          -noinstallsrc -noinstallhdrs -noverify -nosum         \
-         -arch i386 -arch x86_64 -arch ppc                     \
+         -arch i386 -arch x86_64 -arch ppc                     \
          -target All                                           \
-         -project ${PROJECT}                                   \
+         -project ${PROJECT}_darwin-${VERSION}                 \
          -configuration Debug                                  \
          -release $(shell cat /usr/share/buildit/.releaseName) \
-         -othercflags "\"$(SNOW_CFLAGS)\""                     \
+         -othercflags "\"-D_OPEN_SOURCE_\""                    \
 
 #----------------------------------------------------------------------
 #
@@ -47,6 +39,9 @@ snow :
 #----------------------------------------------------------------------
 
 LION_CFLAGS=
+LION_CFLAGS+=-D__MAC_10_8=1070
+LION_CFLAGS+=-D__AVAILABILITY_INTERNAL__MAC_10_8=__attribute__((visibility(\\\"default\\\")))
+LION_CFLAGS+=-DHAVE_REACHABILITY_SERVER=YES
 
 lion :
        /usr/local/bin/buildit .                                \
index eadcad1bf8c5e9697293a88eaaafb3d9709a43f8..667418a8e4895f423917c74c02804cb98938ae03 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>Requires</key>
        <array>
                <string>com.apple.SystemConfiguration.IPConfiguration</string>
                <string>com.apple.SystemConfiguration.PreferencesMonitor</string>
+               <string>com.apple.SystemConfiguration.SCNetworkReachability</string>
        </array>
        <key>Builtin</key>
        <true/>
index f3106a4ccce4ca2397dfff82247cad0042527533..5b0750cf85c6dadb77b7d4e77e374280938762a5 100644 (file)
@@ -11,16 +11,19 @@ shared_dns_infoUser.o: shared_dns_info.h shared_dns_infoUser.c
        cc -I../../dnsinfo -Wall -O0 -g -c shared_dns_infoUser.c
 
 dnsinfo_create.o: shared_dns_info.h ../../dnsinfo/dnsinfo_create.h ../../dnsinfo/dnsinfo_create.c
-       cc -I. -I../../dnsinfo -Wall -O0 -g -c ../../dnsinfo/dnsinfo_create.c
+       cc -I. -I../../dnsinfo -I../../nwi -Wall -O0 -g -c ../../dnsinfo/dnsinfo_create.c
 
 dnsinfo_flatfile.o: ../../dnsinfo/dnsinfo_copy.c ../../dnsinfo/dnsinfo_flatfile.c shared_dns_info.h
-       cc -I../../dnsinfo -D_PATH_RESOLVER_DIR='"/var/tmp/resolver"' -Wall -O0 -g -c ../../dnsinfo/dnsinfo_flatfile.c
+       cc -I../../dnsinfo -I../../nwi -D_PATH_RESOLVER_DIR='"/var/tmp/resolver"' -Wall -O0 -g -c ../../dnsinfo/dnsinfo_flatfile.c
 
 dnsinfo_private.o: ../../dnsinfo/dnsinfo_private.h ../../dnsinfo/dnsinfo_private.c
        cc -I../../dnsinfo -Wall -O0 -g -c ../../dnsinfo/dnsinfo_private.c
 
 dns-configuration.o: dns-configuration.h dns-configuration.c dnsinfo_create.o
-       cc -I. -I../../dnsinfo -DMAIN -Wall -O0 -g -c dns-configuration.c
+       cc -I. -I../../dnsinfo -I../../nwi -DMAIN -Wall -O0 -g -c dns-configuration.c
+
+network_information_priv.o: ../../nwi/network_information_priv.h ../../nwi/network_information_priv.c
+       cc -I. -I../../dnsinfo -I../../nwi -DMAIN -Wall -O0 -g -c ../../nwi/network_information_priv.c
 
 proxy-configuration.o: proxy-configuration.h proxy-configuration.c
        cc -I. -Wall -O0 -g -c proxy-configuration.c
@@ -46,10 +49,10 @@ test_smb: Makefile smb-configuration.h smb-configuration.c
 # ----------
 
 test_ipv4_routelist.o: ip_plugin.c
-       cc -I. -I../../dnsinfo -DTEST_IPV4_ROUTELIST -Wall -O0 -g -c -o test_ipv4_routelist.o ip_plugin.c
+       cc -I. -I../../dnsinfo -I../../nwi -DTEST_IPV4_ROUTELIST -Wall -O0 -g -c -o test_ipv4_routelist.o ip_plugin.c
 
-test_ipv4_routelist: test_ipv4_routelist.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o smb-configuration.o
-       cc -Wall -O0 -g -o test_ipv4_routelist test_ipv4_routelist.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o smb-configuration.o -framework SystemConfiguration -framework CoreFoundation
+test_ipv4_routelist: test_ipv4_routelist.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o network_information_priv.o smb-configuration.o proxy-configuration.o
+       cc -Wall -O0 -g -o test_ipv4_routelist test_ipv4_routelist.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o network_information_priv.o shared_dns_infoUser.o smb-configuration.o proxy-configuration.o -framework SystemConfiguration -framework CoreFoundation
 
 test_ipv4_routelist_reference.txt: test_ipv4_routelist
        sh test_reference.sh create test_ipv4_routelist test_ipv4_routelist_reference.txt test_ipv4_routelist_filter.sh
@@ -60,7 +63,7 @@ test_ipv4_routelist_test: test_ipv4_routelist
 # ----------
 
 IPMonitor.o: ip_plugin.c
-       cc -I. -I../../dnsinfo -DTEST_IPMONITOR -Wall -O0 -g -c -o IPMonitor.o ip_plugin.c
+       cc -I. -I../../dnsinfo -I../../nwi -DTEST_IPMONITOR -Wall -O0 -g -c -o IPMonitor.o ip_plugin.c
 
 IPMonitor: IPMonitor.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o smb-configuration.o
        cc -Wall -O0 -g -o IPMonitor IPMonitor.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o smb-configuration.o -framework SystemConfiguration -framework CoreFoundation
index f60b512bd08676b0c565897bd87cfea12ea7a473..ca9e7bae14ef2237a193653312cbb96517ea9978 100644 (file)
 #include <notify.h>
 extern uint32_t notify_monitor_file(int token, const char *name, int flags);
 #endif // !TARGET_OS_IPHONE
+#include <CommonCrypto/CommonDigest.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <SystemConfiguration/SystemConfiguration.h>
 #include <SystemConfiguration/SCPrivate.h>
 #include <SystemConfiguration/SCValidation.h>
 
+#include "dns-configuration.h"
+
 #include <dnsinfo.h>
 #include <dnsinfo_create.h>
 
@@ -68,6 +71,10 @@ extern uint32_t notify_monitor_file(int token, const char *name, int flags);
 #define        kDNSServiceCompPrivateDNS       "PrivateDNS"
 #endif
 
+#define DNS_CONFIGURATION_FLAGS_KEY    CFSTR("__FLAGS__")
+#define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
+#define DNS_CONFIGURATION_ORDER_KEY    CFSTR("__ORDER__")
+
 /* multicast DNS resolver configurations */
 static CFNumberRef     S_mdns_timeout  = NULL;
 
@@ -79,6 +86,7 @@ static void
 add_resolver(CFMutableArrayRef resolvers, CFMutableDictionaryRef resolver)
 {
        CFIndex         i;
+       CFStringRef     interface;
        CFIndex         n_resolvers;
        CFNumberRef     order;
        uint32_t        order_val       = 0;
@@ -129,10 +137,46 @@ add_resolver(CFMutableArrayRef resolvers, CFMutableDictionaryRef resolver)
                }
        }
 
-       order = CFNumberCreate(NULL, kCFNumberIntType, &n_resolvers);
-       CFDictionarySetValue(resolver, CFSTR("*ORDER*"), order);
+       order = CFNumberCreate(NULL, kCFNumberCFIndexType, &n_resolvers);
+       CFDictionarySetValue(resolver, DNS_CONFIGURATION_ORDER_KEY, order);
        CFRelease(order);
 
+       interface = CFDictionaryGetValue(resolver, kSCPropInterfaceName);
+       if (interface != NULL) {
+               uint32_t        flags;
+               unsigned int    if_index                = 0;
+               char            if_name[IF_NAMESIZE];
+               CFNumberRef     num;
+               CFBooleanRef    val;
+
+               if (_SC_cfstring_to_cstring(interface,
+                                           if_name,
+                                           sizeof(if_name),
+                                           kCFStringEncodingASCII) != NULL) {
+                       if_index = if_nametoindex(if_name);
+               }
+
+               if ((if_index != 0) &&
+                   (
+                    // check if this is a "scoped" configuration
+                    (CFDictionaryGetValueIfPresent(resolver, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
+                     isA_CFNumber(num) &&
+                     CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
+                     (flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)
+                    ||
+                    // check if we should scope all queries with this configuration
+                    (CFDictionaryGetValueIfPresent(resolver, DNS_CONFIGURATION_SCOPED_QUERY_KEY, (const void **)&val) &&
+                     isA_CFBoolean(val) &&
+                     CFBooleanGetValue(val))
+                   )
+                  ) {
+                       // if interface index available and it should be used
+                       num = CFNumberCreate(NULL, kCFNumberIntType, &if_index);
+                       CFDictionarySetValue(resolver, DNS_CONFIGURATION_IF_INDEX_KEY, num);
+                       CFRelease(num);
+               }
+       }
+
        CFArrayAppendValue(resolvers, resolver);
        return;
 }
@@ -384,8 +428,8 @@ compareBySearchOrder(const void *val1, const void *val2, void *context)
 
        if (order1 == order2) {
                // if same "SearchOrder", retain original orderring for configurations
-               if (CFDictionaryGetValueIfPresent(dns1, CFSTR("*ORDER*"), (const void **)&num1) &&
-                   CFDictionaryGetValueIfPresent(dns2, CFSTR("*ORDER*"), (const void **)&num2) &&
+               if (CFDictionaryGetValueIfPresent(dns1, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num1) &&
+                   CFDictionaryGetValueIfPresent(dns2, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num2) &&
                    isA_CFNumber(num1) &&
                    isA_CFNumber(num2) &&
                    CFNumberGetValue(num1, kCFNumberIntType, &order1) &&
@@ -404,7 +448,7 @@ compareBySearchOrder(const void *val1, const void *val2, void *context)
 }
 
 
-static CFArrayRef
+static CF_RETURNS_RETAINED CFArrayRef
 extract_search_domains(CFMutableDictionaryRef defaultDomain, CFArrayRef supplemental)
 {
        CFStringRef             defaultDomainName       = NULL;
@@ -663,7 +707,6 @@ add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArray
        for (i = 0; i < n_order; i++) {
                CFDictionaryRef         dns;
                uint32_t                flags;
-               unsigned int            if_index;
                char                    if_name[IF_NAMESIZE];
                CFStringRef             interface;
                CFMutableDictionaryRef  newDNS;
@@ -700,7 +743,7 @@ add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArray
                                             if_name,
                                             sizeof(if_name),
                                             kCFStringEncodingASCII) == NULL) ||
-                   ((if_index = if_nametoindex(if_name)) == 0)) {
+                   (if_nametoindex(if_name) == 0)) {
                        // if interface index not available
                        continue;
                }
@@ -715,15 +758,15 @@ add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArray
                        CFRelease(searchDomains);
                }
 
-               // set if_index
-               num = CFNumberCreate(NULL, kCFNumberIntType, &if_index);
-               CFDictionarySetValue(newDNS, CFSTR("*IF_INDEX*"), num);
-               CFRelease(num);
-
-               // set "scoped" flag
-               flags = DNS_RESOLVER_FLAGS_SCOPED;
+               // set "scoped" configuration flag(s)
+               if (!CFDictionaryGetValueIfPresent(newDNS, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) ||
+                   !isA_CFNumber(num) ||
+                   !CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
+                       flags = 0;
+               }
+               flags |= DNS_RESOLVER_FLAGS_SCOPED;
                num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags);
-               CFDictionarySetValue(newDNS, CFSTR("*FLAGS*"), num);
+               CFDictionarySetValue(newDNS, DNS_CONFIGURATION_FLAGS_KEY, num);
                CFRelease(num);
 
                // remove keys we don't want in a [scoped] resolver
@@ -784,6 +827,23 @@ add_default_resolver(CFMutableArrayRef     resolvers,
 }
 
 
+/*
+ * rankReachability()
+ *   Not reachable       == 0
+ *   Connection Required == 1
+ *   Reachable           == 2
+ */
+static int
+rankReachability(SCNetworkReachabilityFlags flags)
+{
+       int     rank = 0;
+
+       if (flags & kSCNetworkReachabilityFlagsReachable)               rank = 2;
+       if (flags & kSCNetworkReachabilityFlagsConnectionRequired)      rank = 1;
+       return rank;
+}
+
+
 static dns_create_resolver_t
 create_resolver(CFDictionaryRef dns)
 {
@@ -791,6 +851,9 @@ create_resolver(CFDictionaryRef dns)
        CFNumberRef             num;
        dns_create_resolver_t   _resolver;
        CFStringRef             str;
+       CFMutableArrayRef       serverAddresses         = NULL;
+       CFStringRef             targetInterface         = NULL;
+       unsigned int            targetInterfaceIndex    = 0;
 
        _resolver = _dns_resolver_create();
 
@@ -823,19 +886,42 @@ create_resolver(CFDictionaryRef dns)
                }
        }
 
+       // process interface index
+       num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_IF_INDEX_KEY);
+       if (isA_CFNumber(num)) {
+               int     if_index;
+
+               if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) {
+                       char    if_name[IFNAMSIZ];
+
+                       _dns_resolver_set_if_index(&_resolver, if_index);
+
+                       if ((if_index != 0) &&
+                           (if_indextoname(if_index, if_name) != NULL)) {
+                               targetInterface = CFStringCreateWithCString(NULL,
+                                                                           if_name,
+                                                                           kCFStringEncodingASCII);
+                               targetInterfaceIndex = if_index;
+                       }
+               }
+       }
+
        // process nameserver addresses
        list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
        if (isA_CFArray(list)) {
                CFIndex i;
-               CFIndex n       = CFArrayGetCount(list);
+               CFIndex n       = CFArrayGetCount(list);
+
+               serverAddresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
 
                for (i = 0; i < n; i++) {
                        union {
-                               struct sockaddr         sa;
-                               struct sockaddr_in      sin;
-                               struct sockaddr_in6     sin6;
+                               struct sockaddr         sa;
+                               struct sockaddr_in      sin;
+                               struct sockaddr_in6     sin6;
                        } addr;
-                       char    buf[128];
+                       char                            buf[64];
+                       CFDataRef                       serverAddress;
 
                        str = CFArrayGetValueAtIndex(list, i);
                        if (!isA_CFString(str)) {
@@ -846,27 +932,26 @@ create_resolver(CFDictionaryRef dns)
                                continue;
                        }
 
-                       bzero(&addr, sizeof(addr));
-                       if (inet_aton(buf, &addr.sin.sin_addr) == 1) {
-                               /* if IPv4 address */
-                               addr.sin.sin_len    = sizeof(addr.sin);
-                               addr.sin.sin_family = AF_INET;
-                               _dns_resolver_add_nameserver(&_resolver, &addr.sa);
-                       } else if (inet_pton(AF_INET6, buf, &addr.sin6.sin6_addr) == 1) {
-                               /* if IPv6 address */
-                               char    *p;
-
-                               p = strchr(buf, '%');
-                               if (p != NULL) {
-                                       addr.sin6.sin6_scope_id = if_nametoindex(p + 1);
-                               }
-
-                               addr.sin6.sin6_len    = sizeof(addr.sin6);
-                               addr.sin6.sin6_family = AF_INET6;
-                               _dns_resolver_add_nameserver(&_resolver, &addr.sa);
-                       } else {
+                       if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
                                continue;
                        }
+
+                       if ((addr.sa.sa_family == AF_INET6) &&
+                           (IN6_IS_ADDR_LINKLOCAL(&addr.sin6.sin6_addr) ||
+                            IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6.sin6_addr)) &&
+                           (addr.sin6.sin6_scope_id == 0) &&
+                           (targetInterfaceIndex != 0)) {
+                               // for link local [IPv6] addresses, if the scope id is not
+                               // set then we should use the interface associated with the
+                               // resolver configuration
+                               addr.sin6.sin6_scope_id = targetInterfaceIndex;
+                       }
+
+                       _dns_resolver_add_nameserver(&_resolver, &addr.sa);
+
+                       serverAddress = CFDataCreate(NULL, (const void *)&addr.sa, addr.sa.sa_len);
+                       CFArrayAppendValue(serverAddresses, serverAddress);
+                       CFRelease(serverAddress);
                }
        }
 
@@ -970,18 +1055,8 @@ create_resolver(CFDictionaryRef dns)
                }
        }
 
-       // process interface index
-       num = CFDictionaryGetValue(dns, CFSTR("*IF_INDEX*"));
-       if (isA_CFNumber(num)) {
-               int     if_index;
-
-               if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) {
-                       _dns_resolver_set_if_index(&_resolver, if_index);
-               }
-       }
-
        // process flags
-       num = CFDictionaryGetValue(dns, CFSTR("*FLAGS*"));
+       num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_FLAGS_KEY);
        if (isA_CFNumber(num)) {
                uint32_t        flags;
 
@@ -990,18 +1065,85 @@ create_resolver(CFDictionaryRef dns)
                }
        }
 
+       if (serverAddresses != NULL) {
+               SCNetworkReachabilityFlags      flags           = kSCNetworkReachabilityFlagsReachable;
+               CFIndex                         i;
+               CFIndex                         n               = CFArrayGetCount(serverAddresses);
+               CFMutableDictionaryRef          targetOptions;
+
+               targetOptions = CFDictionaryCreateMutable(NULL,
+                                                         0,
+                                                         &kCFTypeDictionaryKeyCallBacks,
+                                                         &kCFTypeDictionaryValueCallBacks);
+               if (targetInterface != NULL) {
+                       CFDictionarySetValue(targetOptions,
+                                            kSCNetworkReachabilityOptionInterface,
+                                            targetInterface);
+               }
+
+               for (i = 0; i < n; i++) {
+                       SCNetworkReachabilityFlags      ns_flags;
+                       Boolean                         ok;
+                       CFDataRef                       serverAddress;
+                       SCNetworkReachabilityRef        target;
+
+                       serverAddress = CFArrayGetValueAtIndex(serverAddresses, i);
+                       CFDictionarySetValue(targetOptions,
+                                            kSCNetworkReachabilityOptionRemoteAddress,
+                                            serverAddress);
+                       target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
+                       if (target == NULL) {
+                               CFDictionaryRemoveValue(targetOptions, kSCNetworkReachabilityOptionInterface);
+                               target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
+                               if (target != NULL) {
+                                       // if interface name not (no longer) valid
+                                       CFRelease(target);
+                                       flags = 0;
+                                       break;
+                               }
+
+                               // address not valid?
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("create_resolver SCNetworkReachabilityCreateWithOptions() failed:\n  options = %@"),
+                                     targetOptions);
+                               break;
+                       }
+
+                       ok = SCNetworkReachabilityGetFlags(target, &ns_flags);
+                       CFRelease(target);
+                       if (!ok) {
+                               break;
+                       }
+
+                       if ((i == 0) ||
+                           (rankReachability(ns_flags) < rankReachability(flags))) {
+                               /* return the worst case result */
+                               flags = ns_flags;
+                       }
+               }
+
+               _dns_resolver_set_reach_flags(&_resolver, flags);
+
+               CFRelease(targetOptions);
+               CFRelease(serverAddresses);
+       }
+
+       if (targetInterface != NULL) {
+               CFRelease(targetInterface);
+       }
+
        return _resolver;
 }
 
 
 static __inline__ Boolean
-isScopedDNS(CFDictionaryRef dns)
+isScopedConfiguration(CFDictionaryRef dns)
 {
        uint32_t        flags;
        CFNumberRef     num;
 
        if ((dns != NULL) &&
-           CFDictionaryGetValueIfPresent(dns, CFSTR("*FLAGS*"), (const void **)&num) &&
+           CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
            (num != NULL) &&
            CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
            ((flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)) {
@@ -1039,8 +1181,8 @@ compareDomain(const void *val1, const void *val2, void *context)
        }
 
        // sort non-scoped before scoped
-       scoped1 = isScopedDNS(dns1);
-       scoped2 = isScopedDNS(dns2);
+       scoped1 = isScopedConfiguration(dns1);
+       scoped2 = isScopedConfiguration(dns2);
        if (scoped1 != scoped2) {
                if (!scoped1) {
                        return kCFCompareLessThan;
@@ -1103,19 +1245,23 @@ compareDomain(const void *val1, const void *val2, void *context)
 
 
 __private_extern__
-void
+Boolean
 dns_configuration_set(CFDictionaryRef   defaultResolver,
                      CFDictionaryRef   services,
                      CFArrayRef        serviceOrder,
                      CFArrayRef        multicastResolvers,
                      CFArrayRef        privateResolvers)
 {
+       dns_create_config_t     _config;
+       Boolean                 changed         = FALSE;
        CFIndex                 i;
        CFMutableDictionaryRef  myDefault;
        Boolean                 myOrderAdded    = FALSE;
        CFArrayRef              mySearchDomains = NULL;
        CFIndex                 n_resolvers;
        CFMutableArrayRef       resolvers;
+       unsigned char           signature[CC_SHA1_DIGEST_LENGTH];
+       static unsigned char    signature_last[CC_SHA1_DIGEST_LENGTH];
 
        // establish list of resolvers
 
@@ -1178,9 +1324,9 @@ dns_configuration_set(CFDictionaryRef   defaultResolver,
 
                resolver = CFArrayGetValueAtIndex(resolvers, 1);
                if (CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) ||
-                   isScopedDNS(resolver)) {
+                   isScopedConfiguration(resolver)) {
                        // if not a supplemental "default" resolver (a domain name is
-                       // present) or a if it's a scoped resolver
+                       // present) or if it's a scoped configuration
                        CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
                }
        }
@@ -1193,12 +1339,8 @@ dns_configuration_set(CFDictionaryRef   defaultResolver,
                /*
                 * if no default and no supplemental/scoped resolvers
                 */
-               if (!_dns_configuration_store(NULL)) {
-                       SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
-               }
+               _config = NULL;
        } else {
-               dns_create_config_t     _config;
-
                /*
                 * if default and/or supplemental/scoped resolvers are defined
                 */
@@ -1221,18 +1363,23 @@ dns_configuration_set(CFDictionaryRef   defaultResolver,
 
                _dnsinfo_flatfile_add_resolvers(&_config);
 #endif // !TARGET_OS_IPHONE
+       }
 
-               // save configuration
-
-               if (!_dns_configuration_store(&_config)) {
-                       SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
-               }
+       // check if the configuration changed
+       _dns_configuration_signature(&_config, signature, sizeof(signature));
+       if (bcmp(signature, signature_last, sizeof(signature)) != 0) {
+               changed = TRUE;
+       }
+       bcopy(signature, signature_last, sizeof(signature));
 
-               _dns_configuration_free(&_config);
+       // save configuration
+       if (!_dns_configuration_store(&_config)) {
+               SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
        }
+       if (_config != NULL) _dns_configuration_free(&_config);
 
        CFRelease(resolvers);
-       return;
+       return changed;
 }
 
 
@@ -1334,6 +1481,10 @@ dns_configuration_init(CFBundleRef bundle)
 }
 
 
+#pragma mark -
+#pragma mark Standalone test code
+
+
 #ifdef MAIN
 
 static void
@@ -1510,11 +1661,11 @@ main(int argc, char **argv)
 
        // update DNS configuration
        dns_configuration_init(CFBundleGetMainBundle());
-       dns_configuration_set(primaryDNS,
-                             service_state_dict,
-                             service_order,
-                             multicast_resolvers,
-                             private_resolvers);
+       (void)dns_configuration_set(primaryDNS,
+                                   service_state_dict,
+                                   service_order,
+                                   multicast_resolvers,
+                                   private_resolvers);
 
        // cleanup
        if (setup_global_ipv4 != NULL)  CFRelease(setup_global_ipv4);
index 51062b020f7e4c9723a8957fa6f2f787849f6e0a..08dc9e10f171ea55fbcdf458d11f90ce4ee2882c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2006, 2008, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <sys/cdefs.h>
 #include <CoreFoundation/CoreFoundation.h>
 
+
+#define DNS_CONFIGURATION_SCOPED_QUERY_KEY     CFSTR("__SCOPED_QUERY__")
+
+
 __BEGIN_DECLS
 
+__private_extern__
 void   dns_configuration_init          (CFBundleRef            bundle);
 
 
 #if    !TARGET_OS_IPHONE
+__private_extern__
 void   dns_configuration_monitor       (SCDynamicStoreRef      store,
                                         SCDynamicStoreCallBack callout);
 #endif // !TARGET_OS_IPHONE
 
-void   dns_configuration_set           (CFDictionaryRef        defaultResolver,
+__private_extern__
+Boolean        dns_configuration_set           (CFDictionaryRef        defaultResolver,
                                         CFDictionaryRef        services,
                                         CFArrayRef             serviceOrder,
                                         CFArrayRef             multicastResolvers,
index 82cd44bf81846c674691d6c3d12cbca47b89c39a..cb683f422b4179feee7cde7d3066973557e9d9d6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2011 Apple Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2012 Apple Inc.  All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -87,6 +87,7 @@
 #include <sys/sysctl.h>
 #include <limits.h>
 #include <notify.h>
+#include <mach/mach_time.h>
 
 #include <SystemConfiguration/SystemConfiguration.h>
 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
 #ifndef        kDNSServiceCompPrivateDNS
 #define        kDNSServiceCompPrivateDNS       "PrivateDNS"
 #endif
+#include <network_information.h>
+#include "network_information_priv.h"
 
 enum {
     kProtocolFlagsNone         = 0x0,
@@ -117,7 +120,7 @@ enum {
     kDebugFlag2                = 0x00000002,
     kDebugFlag4                = 0x00000004,
     kDebugFlag8                = 0x00000008,
-    kDebugFlagDefault  = kDebugFlag1,
+    kDebugFlagDefault  = kDebugFlag1,
     kDebugFlagAll      = 0xffffffff
 };
 
@@ -140,13 +143,6 @@ enum {
 #define IP_CH(ip)      ((u_char *)(ip))
 #define IP_LIST(ip)    IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
 
-typedef uint32_t       Rank;
-
-enum {
-    kRankFirst         = 0,
-    kRankLast          = UINT_MAX
-};
-
 /*
  * IPv4 Route management
  */
@@ -154,13 +150,9 @@ enum {
 typedef uint32_t       RouteFlags;
 
 enum {
-    kRouteIsDirectToInterfaceFlag      = 0x00000001,
-    kRouteIsNotSubnetLocalFlag                 = 0x00000002,
-    kRouteChooseFirstFlag              = 0x00000004,
-    kRouteChooseLastFlag               = 0x00000008,
-    kRouteChooseNeverFlag              = 0x00000010,
-    kRouteIsScopedFlag                 = 0x00000020,
-    kRouteWantScopedFlag               = (kRouteChooseNeverFlag|kRouteIsScopedFlag),
+    kRouteIsDirectToInterfaceFlag      = 0x00000001,
+    kRouteIsNotSubnetLocalFlag         = 0x00000002,
+    kRouteIsScopedFlag                 = 0x00000004,
 };
 
 typedef struct {
@@ -185,6 +177,59 @@ enum {
     kIPv4RouteListRemoveRouteCommand
 };
 
+typedef struct {
+    char               ifname[IFNAMSIZ];
+    uint32_t           flags;
+    Rank               rank;
+    struct in6_addr    iaddr6;
+} IPv6RankedE, *IPv6RankedERef;
+
+typedef struct {
+    int                        count;
+    int                        size;
+    IPv6RankedE                elem[1];
+} IPv6RankedList, *IPv6RankedListRef;
+
+/*
+ * Type: Rank
+ * Purpose:
+ *   A 32-bit value to encode the relative rank of a service.
+ *
+ *   The top 8 bits are used to hold the rank assertion (first, last, never, default),
+ *   the bottom 24 bits are used to store the service index i.e. the position within
+ *   the service order array.
+ */
+#define RANK_ASSERTION_MAKE(r)         ((Rank)(r) << 24)
+#define kRankAssertionFirst            RANK_ASSERTION_MAKE(0)
+#define kRankAssertionDefault          RANK_ASSERTION_MAKE(1)
+#define kRankAssertionLast             RANK_ASSERTION_MAKE(2)
+#define kRankAssertionNever            RANK_ASSERTION_MAKE(3)
+#define kRankAssertionMask             RANK_ASSERTION_MAKE(0xff)
+#define RANK_ASSERTION_MASK(r)         ((Rank)(r) & kRankAssertionMask)
+
+#define RANK_INDEX_MAKE(r)             ((Rank)(r))
+#define kRankIndexMask                 RANK_INDEX_MAKE(0xffffff)
+#define RANK_INDEX_MASK(r)             ((Rank)(r) & kRankIndexMask)
+
+static __inline__ Rank
+RankMake(uint32_t service_index, Rank primary_rank)
+{
+    return (RANK_INDEX_MASK(service_index) | RANK_ASSERTION_MASK(primary_rank));
+}
+
+static __inline__ Rank
+PrimaryRankGetRankAssertion(CFStringRef primaryRank)
+{
+    if (CFEqual(primaryRank, kSCValNetServicePrimaryRankNever)) {
+       return kRankAssertionNever;
+    } else if (CFEqual(primaryRank, kSCValNetServicePrimaryRankFirst)) {
+       return kRankAssertionFirst;
+    } else if (CFEqual(primaryRank, kSCValNetServicePrimaryRankLast)) {
+       return kRankAssertionLast;
+    }
+    return kRankAssertionDefault;
+}
+
 typedef uint32_t       IPv4RouteListApplyCommand;
 
 typedef void IPv4RouteListApplyCallBackFunc(IPv4RouteListApplyCommand cmd,
@@ -211,6 +256,9 @@ static CFMutableDictionaryRef       S_service_state_dict = NULL;
 static CFMutableDictionaryRef  S_ipv4_service_rank_dict = NULL;
 static CFMutableDictionaryRef  S_ipv6_service_rank_dict = NULL;
 
+/* dictionary to hold per-interface rank information */
+static CFMutableDictionaryRef  S_if_rank_dict = NULL;
+
 /* if set, a PPP interface overrides the primary */
 static boolean_t               S_ppp_override_primary = FALSE;
 
@@ -238,6 +286,8 @@ static const struct in6_addr        S_ip6_zeros = IN6ADDR_ANY_INIT;
 
 static boolean_t               S_append_state = FALSE;
 
+static nwi_state_t             S_nwi_state = NULL;
+
 #if    !TARGET_OS_IPHONE
 static CFStringRef             S_primary_smb = NULL;
 static CFStringRef             S_state_global_smb = NULL;
@@ -249,7 +299,7 @@ static CFStringRef          S_state_global_smb = NULL;
 
 #ifndef KERN_NETBOOT
 #define KERN_NETBOOT           40      /* int: are we netbooted? 1=yes,0=no */
-#endif KERN_NETBOOT
+#endif //KERN_NETBOOT
 
 /**
  ** entityType*, GetEntityChanges*
@@ -278,6 +328,51 @@ static const CFStringRef *entityTypeNames[ENTITY_TYPES_COUNT] = {
 #endif /* !TARGET_OS_IPHONE */
 };
 
+#ifndef kSCEntNetIPv4RouteList
+#define kSCEntNetIPv4RouteList CFSTR("IPv4RouteList")
+#endif
+
+#ifndef kSCEntNetIPv4ServiceDict
+#define kSCEntNetIPv4ServiceDict CFSTR("IPv4ServiceDict")
+#endif
+
+static IPv4RouteListRef
+ipv4_dict_get_routelist(CFDictionaryRef ipv4_dict)
+{
+    CFDataRef          routes;
+    IPv4RouteListRef   routes_list = NULL;
+
+    if (isA_CFDictionary(ipv4_dict) == NULL) {
+       return (NULL);
+    }
+
+    routes = CFDictionaryGetValue(ipv4_dict, kSCEntNetIPv4RouteList);
+
+    if (routes != NULL) {
+       routes_list = (IPv4RouteListRef)(void*)CFDataGetBytePtr(routes);
+    }
+    return (routes_list);
+}
+
+static CFStringRef
+ipv4_dict_get_ifname(CFDictionaryRef ipv4_dict)
+{
+    CFDictionaryRef ipv4_service_dict = NULL;
+
+    if (isA_CFDictionary(ipv4_dict) == NULL) {
+       return (NULL);
+    }
+
+    ipv4_service_dict = CFDictionaryGetValue(ipv4_dict,
+                                            kSCEntNetIPv4ServiceDict);
+
+    if (isA_CFDictionary(ipv4_service_dict) == NULL) {
+       return NULL;
+    }
+
+    return CFDictionaryGetValue(ipv4_service_dict, kSCPropInterfaceName);
+}
+
 typedef boolean_t GetEntityChangesFunc(CFStringRef serviceID,
                                       CFDictionaryRef state_dict,
                                       CFDictionaryRef setup_dict,
@@ -322,6 +417,27 @@ typedef struct {
     CFMutableDictionaryRef     set;
 } keyChangeList, * keyChangeListRef;
 
+static CFStringRef
+my_CFStringCopyComponent(CFStringRef path, CFStringRef separator,
+                        CFIndex component_index)
+{
+    CFArrayRef                 arr;
+    CFStringRef                        component = NULL;
+
+    arr = CFStringCreateArrayBySeparatingStrings(NULL, path, separator);
+    if (arr == NULL) {
+       goto done;
+    }
+    if (CFArrayGetCount(arr) <= component_index) {
+       goto done;
+    }
+    component = CFRetain(CFArrayGetValueAtIndex(arr, component_index));
+
+ done:
+    my_CFRelease(&arr);
+    return (component);
+}
+
 static void
 keyChangeListInit(keyChangeListRef keys)
 {
@@ -366,7 +482,8 @@ keyChangeListSetValue(keyChangeListRef keys, CFStringRef key, CFTypeRef value)
 }
 
 static void
-keyChangeListApplyToStore(keyChangeListRef keys, SCDynamicStoreRef session)
+keyChangeListApplyToStore(keyChangeListRef keys, SCDynamicStoreRef session,
+                         CFStringRef network_change_msg)
 {
     CFArrayRef         notify = keys->notify;
     CFArrayRef         remove = keys->remove;
@@ -403,7 +520,11 @@ keyChangeListApplyToStore(keyChangeListRef keys, SCDynamicStoreRef session)
 
     status = notify_post("com.apple.system.config.network_change");
     if (status == NOTIFY_STATUS_OK) {
-       SCLog(TRUE, LOG_NOTICE, CFSTR("network configuration changed."));
+       if (CFStringGetLength(network_change_msg) != 0) {
+           SCLog(TRUE, LOG_NOTICE, CFSTR("network changed:%@"), network_change_msg);
+       } else {
+           SCLog(TRUE, LOG_NOTICE, CFSTR("network changed."));
+       }
     } else {
        SCLog(TRUE, LOG_NOTICE,
              CFSTR("IPMonitor: notify_post() failed: error=%ld"), status);
@@ -597,7 +718,7 @@ cfstring_to_ip6(CFStringRef str, struct in6_addr * ip6_p)
     return (cfstring_to_ipvx(AF_INET6, str, ip6_p, sizeof(*ip6_p)));
 }
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 setup_service_key(CFStringRef serviceID, CFStringRef entity)
 {
     return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
@@ -606,7 +727,7 @@ setup_service_key(CFStringRef serviceID, CFStringRef entity)
                                                        entity));
 }
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 state_service_key(CFStringRef serviceID, CFStringRef entity)
 {
     return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
@@ -616,27 +737,27 @@ state_service_key(CFStringRef serviceID, CFStringRef entity)
 }
 
 static CFDictionaryRef
-get_service_setup_entity(CFDictionaryRef service_info, CFStringRef serviceID,
+get_service_setup_entity(CFDictionaryRef services_info, CFStringRef serviceID,
                         CFStringRef entity)
 {
     CFStringRef                setup_key;
     CFDictionaryRef    setup_dict;
 
     setup_key = setup_service_key(serviceID, entity);
-    setup_dict = my_CFDictionaryGetDictionary(service_info, setup_key);
+    setup_dict = my_CFDictionaryGetDictionary(services_info, setup_key);
     my_CFRelease(&setup_key);
     return (setup_dict);
 }
 
 static CFDictionaryRef
-get_service_state_entity(CFDictionaryRef service_info, CFStringRef serviceID,
+get_service_state_entity(CFDictionaryRef services_info, CFStringRef serviceID,
                         CFStringRef entity)
 {
     CFStringRef                state_key;
     CFDictionaryRef    state_dict;
 
     state_key = state_service_key(serviceID, entity);
-    state_dict = my_CFDictionaryGetDictionary(service_info, state_key);
+    state_dict = my_CFDictionaryGetDictionary(services_info, state_key);
     my_CFRelease(&state_key);
     return (state_dict);
 }
@@ -690,35 +811,12 @@ subnet_addr(struct in_addr addr, struct in_addr mask)
     return (net);
 }
 
-static __inline__ int
-uint32_cmp(uint32_t a, uint32_t b)
-{
-    int                ret;
-
-    if (a == b) {
-       ret = 0;
-    }
-    else if (a < b) {
-       ret = -1;
-    }
-    else {
-       ret = 1;
-    }
-    return (ret);
-}
-
 static __inline__ int
 in_addr_cmp(struct in_addr a, struct in_addr b)
 {
     return (uint32_cmp(ntohl(a.s_addr), ntohl(b.s_addr)));
 }
 
-static __inline__ int
-RankCompare(Rank a, Rank b)
-{
-    return (uint32_cmp(a, b));
-}
-
 static __inline__ int
 RouteFlagsCompare(RouteFlags a, RouteFlags b)
 {
@@ -728,6 +826,8 @@ RouteFlagsCompare(RouteFlags a, RouteFlags b)
 static void
 IPv4RouteCopyDescriptionWithString(IPv4RouteRef r, CFMutableStringRef str)
 {
+    Rank rank_assertion = RANK_ASSERTION_MASK(r->rank);
+
     CFStringAppendFormat(str, NULL,
                         CFSTR("Dest " IP_FORMAT
                               " Mask " IP_FORMAT
@@ -744,21 +844,24 @@ IPv4RouteCopyDescriptionWithString(IPv4RouteRef r, CFMutableStringRef str)
     else if ((r->flags & kRouteIsDirectToInterfaceFlag) != 0) {
        CFStringAppend(str, CFSTR(" [direct]"));
     }
-    if ((r->flags & kRouteChooseFirstFlag) != 0) {
-       CFStringAppend(str, CFSTR(" [first]"));
-    }
-    if ((r->flags & kRouteChooseLastFlag) != 0) {
-       CFStringAppend(str, CFSTR(" [last]"));
-    }
-    if ((r->flags & kRouteChooseNeverFlag) != 0) {
-       CFStringAppend(str, CFSTR(" [never]"));
+
+    switch(rank_assertion) {
+       case kRankAssertionFirst:
+           CFStringAppend(str, CFSTR(" [first]"));
+           break;
+       case kRankAssertionLast:
+           CFStringAppend(str, CFSTR(" [last]"));
+           break;
+       case kRankAssertionNever:
+           CFStringAppend(str, CFSTR(" [never]"));
+           break;
+       default:
+           break;
     }
+
     if ((r->flags & kRouteIsScopedFlag) != 0) {
        CFStringAppend(str, CFSTR(" [SCOPED]"));
     }
-    else if ((r->flags & kRouteWantScopedFlag) != 0) {
-       CFStringAppend(str, CFSTR(" [SCOPED*]"));
-    }
     return;
 }
 
@@ -777,7 +880,7 @@ IPv4RoutePrint(IPv4RouteRef route)
 {
     CFStringRef        str = IPv4RouteCopyDescription(route);
 
-    SCPrint(TRUE, stdout, CFSTR("%@"), str);
+    SCPrint(TRUE, stdout, CFSTR("%@\n"), str);
     CFRelease(str);
     return;
 }
@@ -809,49 +912,10 @@ IPv4RouteCompare(IPv4RouteRef a, Rank a_rank,
                cmp = 0;
            }
            else {
-               boolean_t a_never = (a->flags & kRouteChooseNeverFlag) != 0;
-               boolean_t b_never = (b->flags & kRouteChooseNeverFlag) != 0;
                *same_dest = TRUE;
-
-               if (a_never != b_never) {
-                   if (a_never) {
-                       cmp = 1;
-                   }
-                   else {
-                       cmp = -1;
-                   }
-               }
-               else {
-                   boolean_t a_last = (a->flags & kRouteChooseLastFlag) != 0;
-                   boolean_t b_last = (b->flags & kRouteChooseLastFlag) != 0;
-
-                   if (a_last != b_last) {
-                       if (a_last) {
-                           cmp = 1;
-                       }
-                       else {
-                           cmp = -1;
-                       }
-                   }
-                   else {
-                       boolean_t a_first = (a->flags & kRouteChooseFirstFlag) != 0;
-                       boolean_t b_first = (b->flags & kRouteChooseFirstFlag) != 0;
-
-                       if (a_first != b_first) {
-                           if (a_first) {
-                               cmp = -1;
-                           }
-                           else {
-                               cmp = 1;
-                           }
-                       }
-                       else {
-                           cmp = RankCompare(a_rank, b_rank);
-                           if (cmp == 0) {
-                               cmp = name_cmp;
-                           }
-                       }
-                   }
+               cmp = RankCompare(a_rank, b_rank);
+               if (cmp == 0) {
+                   cmp = name_cmp;
                }
            }
        }
@@ -880,7 +944,7 @@ IPv4RouteCompare(IPv4RouteRef a, Rank a_rank,
     return (cmp);
 }
 
-static CFStringRef
+static CFMutableStringRef
 IPv4RouteListCopyDescription(IPv4RouteListRef routes)
 {
     int                        i;
@@ -894,7 +958,7 @@ IPv4RouteListCopyDescription(IPv4RouteListRef routes)
        CFStringAppendFormat(str, NULL, CFSTR("\n%2d. "), i);
        IPv4RouteCopyDescriptionWithString(r, str);
     }
-    CFStringAppend(str, CFSTR("\n}\n"));
+    CFStringAppend(str, CFSTR("\n}"));
     return (str);
 }
 
@@ -903,7 +967,7 @@ IPv4RouteListPrint(IPv4RouteListRef routes)
 {
     CFStringRef        str = IPv4RouteListCopyDescription(routes);
 
-    SCPrint(TRUE, stdout, CFSTR("%@"), str);
+    SCPrint(TRUE, stdout, CFSTR("%@\n"), str);
     CFRelease(str);
     return;
 }
@@ -936,26 +1000,10 @@ IPv4RouteListFindRoute(IPv4RouteListRef routes, IPv4RouteRef route)
            && (scan->mask.s_addr == route->mask.s_addr)
            && (strcmp(scan->ifname, route->ifname) == 0)
            && (scan->ifa.s_addr == route->ifa.s_addr)
-           && (scan->gateway.s_addr == route->gateway.s_addr)) {
-           /*
-            * So far, the routes look the same.  If the flags
-            * are also equiv than we've found a match.
-            */
-           RouteFlags  r_flags;
-           RouteFlags  s_flags;
-
-           s_flags = scan->flags;
-           if ((s_flags & kRouteWantScopedFlag) != 0) {
-               s_flags |= kRouteWantScopedFlag;
-           }
-           r_flags = route->flags;
-           if ((r_flags & kRouteWantScopedFlag) != 0) {
-               r_flags |= kRouteWantScopedFlag;
-           }
-           if (s_flags == r_flags) {
+           && (scan->gateway.s_addr == route->gateway.s_addr)
+           && (scan->flags == route->flags)) {
                scan_result = scan;
                break;
-           }
        }
     }
     return (scan_result);
@@ -1025,7 +1073,7 @@ IPv4RouteListApply(IPv4RouteListRef old_routes, IPv4RouteListRef new_routes,
 enum {
     kScopeNone = 0,
     kScopeThis = 1,
-    kScopeNext         = 2
+    kScopeNext = 2
 };
 
 static IPv4RouteListRef
@@ -1033,6 +1081,7 @@ IPv4RouteListAddRoute(IPv4RouteListRef routes, int init_size,
                      IPv4RouteRef this_route, Rank this_rank)
 {
     int                        i;
+    IPv4RouteRef       first_scan = NULL;
     int                        scope_which = kScopeNone;
     IPv4RouteRef       scan;
     int                        where = -1;
@@ -1048,9 +1097,15 @@ IPv4RouteListAddRoute(IPv4RouteListRef routes, int init_size,
        boolean_t       same_dest;
 
        cmp = IPv4RouteCompare(this_route, this_rank, scan, scan->rank, &same_dest);
+
+       if (same_dest == TRUE && first_scan == NULL) {
+           first_scan = scan;
+       }
+
        if (cmp < 0) {
            if (where == -1) {
-               if (same_dest == TRUE) {
+               if (same_dest == TRUE
+                   && (first_scan->flags & kRouteIsScopedFlag) == 0) {
                    if ((scan->flags & kRouteIsScopedFlag) != 0) {
                        ROUTELIST_DEBUG(("Hit 1: set scope on self\n"),
                                        kDebugFlag8);
@@ -1184,7 +1239,7 @@ static IPv4RouteListRef
 IPv4RouteListAddRouteList(IPv4RouteListRef routes, int init_size,
                          IPv4RouteListRef service_routes, Rank rank)
 {
-    int                i;
+    int                        i;
     IPv4RouteRef       scan;
 
     for (i = 0, scan = service_routes->list;
@@ -1239,6 +1294,7 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes,
     IPv4RouteRef       r;
     struct in_addr     subnet = { 0 };
     struct in_addr     router = { 0 };
+    Rank               rank = kRankAssertionDefault;
 
     if (dict == NULL) {
        return (NULL);
@@ -1275,7 +1331,8 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes,
        return (NULL);
     }
     if (router.s_addr == 0) {
-       flags |= kRouteIsDirectToInterfaceFlag | kRouteChooseLastFlag;
+       flags |= kRouteIsDirectToInterfaceFlag;
+       rank = kRankAssertionLast;
     }
     else {
        /*
@@ -1287,17 +1344,16 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes,
            flags |= kRouteIsDirectToInterfaceFlag;
        }
        if (primaryRank != NULL) {
-           if (CFEqual(primaryRank, kSCValNetServicePrimaryRankNever)) {
-               flags |= kRouteChooseNeverFlag;
-           } else if (CFEqual(primaryRank, kSCValNetServicePrimaryRankFirst)) {
-               flags |= kRouteChooseFirstFlag;
-           } else if (CFEqual(primaryRank, kSCValNetServicePrimaryRankLast)) {
-               flags |= kRouteChooseLastFlag;
-           }
+           rank = PrimaryRankGetRankAssertion(primaryRank);
        } else if (get_override_primary(dict)) {
-           flags |= kRouteChooseFirstFlag;
+           rank = kRankAssertionFirst;
        }
     }
+
+    if (rank == kRankAssertionNever) {
+       flags |= kRouteIsScopedFlag;
+    }
+
     if (add_subnet && (flags & kRouteIsDirectToInterfaceFlag) == 0
        && subnet.s_addr != subnet_addr(router, mask).s_addr) {
        flags |= kRouteIsNotSubnetLocalFlag;
@@ -1330,6 +1386,10 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes,
        else {
            r->gateway = addr;
        }
+       r->rank = rank;
+       if (r->rank == kRankAssertionNever) {
+           r->flags |= kRouteIsScopedFlag;
+       }
        r++;
     }
 
@@ -1341,7 +1401,10 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes,
        r->mask = mask;
        strlcpy(r->ifname, ifn, sizeof(r->ifname));
        r->ifa = addr;
-       r->flags = flags & (kRouteChooseFirstFlag|kRouteChooseLastFlag|kRouteChooseNeverFlag);
+       r->rank = rank;
+       if (r->rank == kRankAssertionNever) {
+           r->flags |= kRouteIsScopedFlag;
+       }
     }
 
     return (routes);
@@ -1360,7 +1423,7 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes,
  * 2. key = "a/b/c" prefix = "a/b/"
  *    returns "c"
  */
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 parse_component(CFStringRef key, CFStringRef prefix)
 {
     CFMutableStringRef comp;
@@ -1407,14 +1470,29 @@ static void
 dump_service_entity(CFStringRef serviceID, CFStringRef entity,
                    CFStringRef operation, CFTypeRef val)
 {
-    CFStringRef        this_val = NULL;
 
-    if (isA_CFData(val) && CFEqual(entity, kSCEntNetIPv4)) {
-       this_val = IPv4RouteListCopyDescription((IPv4RouteListRef)
-                                               CFDataGetBytePtr(val));
-       if (this_val != NULL) {
-           val = this_val;
+    CFDataRef  route_list;
+    CFMutableStringRef this_val = NULL;
+
+    if (CFEqual(entity, kSCEntNetIPv4) && isA_CFDictionary(val) != NULL) {
+       CFDictionaryRef    service_dict = NULL;
+
+       route_list = CFDictionaryGetValue(val, kSCEntNetIPv4RouteList);
+       if (route_list != NULL) {
+           /* ALIGN: CF should align to at least 8-byte boundaries */
+           this_val = IPv4RouteListCopyDescription((IPv4RouteListRef)
+                                                   (void *)CFDataGetBytePtr(route_list));
+       }
+
+       service_dict = CFDictionaryGetValue(val, kSCEntNetIPv4ServiceDict);
+
+       if (service_dict != NULL && isA_CFDictionary(service_dict) != NULL) {
+           if (this_val == NULL) {
+               this_val = CFStringCreateMutable(NULL, 0);
+           }
+           CFStringAppendFormat(this_val, NULL, CFSTR("\n <IPv4Dictionary>: %@"), service_dict);
        }
+       val = this_val;
     }
     if (val == NULL) {
        val = CFSTR("<none>");
@@ -1479,6 +1557,42 @@ service_dict_get(CFStringRef serviceID, CFStringRef entity)
     return (CFDictionaryGetValue(service_dict, entity));
 }
 
+#ifndef kSCPropNetHostname
+#define kSCPropNetHostname CFSTR("Hostname")
+#endif
+
+__private_extern__
+CFStringRef
+copy_dhcp_hostname(CFStringRef serviceID)
+{
+    CFDictionaryRef    dict = NULL;
+    CFStringRef                hostname = NULL;
+    CFDictionaryRef    service_dict = NULL;
+
+    dict = service_dict_get(serviceID, kSCEntNetIPv4);
+
+    if (dict == NULL || isA_CFDictionary(dict) == NULL) {
+       return (NULL);
+    }
+
+    service_dict =
+       CFDictionaryGetValue(dict, kSCEntNetIPv4ServiceDict);
+
+    if (service_dict == NULL
+       || isA_CFDictionary(service_dict) == NULL) {
+       return (NULL);
+    }
+
+    hostname =
+       CFDictionaryGetValue(service_dict, kSCPropNetHostname);
+
+    if (hostname != NULL) {
+       CFRetain(hostname);
+    }
+
+    return (hostname);
+}
+
 static boolean_t
 ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val)
 {
@@ -1486,7 +1600,7 @@ ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val)
     int                        if_index;
     char               ifn[IFNAMSIZ];
     CFStringRef                new_router = NULL;
-    char               ntopbuf[INET6_ADDRSTRLEN];
+    char               ntopbuf[INET6_ADDRSTRLEN];
     CFDictionaryRef    old_val = NULL;
     CFStringRef                old_router = NULL;
     struct in6_addr    router_ip;
@@ -1524,7 +1638,8 @@ ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val)
        && (new_router == NULL || CFEqual(old_router, new_router) == FALSE)) {
        /* remove the old Router */
        if (cfstring_to_ip6(old_router, &router_ip)) {
-           if (IN6_IS_ADDR_LINKLOCAL(&router_ip)) {
+           if (IN6_IS_ADDR_LINKLOCAL(&router_ip) ||
+               IN6_IS_ADDR_MC_LINKLOCAL(&router_ip)) {
                /* scope it */
                router_ip.__u6_addr.__u6_addr16[1] = htons(if_index);
            }
@@ -1549,7 +1664,8 @@ ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val)
     }
     /* add the new Router */
     if (cfstring_to_ip6(new_router, &router_ip)) {
-       if (IN6_IS_ADDR_LINKLOCAL(&router_ip)) {
+       if (IN6_IS_ADDR_LINKLOCAL(&router_ip) ||
+           IN6_IS_ADDR_MC_LINKLOCAL(&router_ip)) {
            /* scope it */
            router_ip.__u6_addr.__u6_addr16[1] = htons(if_index);
        }
@@ -1580,7 +1696,7 @@ ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val)
 
 #define        ALLOW_EMPTY_STRING      0x1
 
-static CFTypeRef
+static CF_RETURNS_RETAINED CFTypeRef
 sanitize_prop(CFTypeRef val, uint32_t flags)
 {
     if (val != NULL) {
@@ -1701,13 +1817,15 @@ static boolean_t
 get_ipv4_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
                 CFDictionaryRef setup_dict, CFDictionaryRef info)
 {
+    CFDictionaryRef            aggregated_dict = NULL;
     boolean_t                  changed         = FALSE;
     CFMutableDictionaryRef     dict            = NULL;
     CFStringRef                        primaryRank     = NULL;
     IPv4RouteListRef           r;
 #define R_STATIC               3
     IPv4RouteListRef           routes;
-    char                       routes_buf[IPv4RouteListComputeSize(R_STATIC)];
+    /* ALIGN: force align */
+    uint32_t                   routes_buf[roundup(IPv4RouteListComputeSize(R_STATIC), sizeof(uint32_t))];
     CFDataRef                  routes_data     = NULL;
     CFDictionaryRef            service_options;
 
@@ -1732,7 +1850,7 @@ get_ipv4_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
                                 router);
        }
     }
-    routes = (IPv4RouteListRef)routes_buf;
+    routes = (IPv4RouteListRef)(void *)routes_buf;
     routes->size = R_STATIC;
     routes->count = 0;
     r = IPv4RouteListCreateWithDictionary(routes, dict, primaryRank);
@@ -1751,12 +1869,30 @@ get_ipv4_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
              dict);
     }
   done:
-    changed = service_dict_set(serviceID, kSCEntNetIPv4, routes_data);
+    if (routes_data != NULL) {
+       CFStringRef     keys[2];
+       CFTypeRef       values[2];
+
+       keys[0] = kSCEntNetIPv4ServiceDict;
+       values[0] = dict;
+       keys[1] = kSCEntNetIPv4RouteList;
+       values[1] = routes_data;
+
+       aggregated_dict = CFDictionaryCreate(NULL,
+                                            (const void**)keys,
+                                            values,
+                                            sizeof(keys)/sizeof(keys[0]),
+                                            &kCFTypeDictionaryKeyCallBacks,
+                                            &kCFTypeDictionaryValueCallBacks);
+
+    }
+    changed = service_dict_set(serviceID, kSCEntNetIPv4, aggregated_dict);
     if (routes_data == NULL) {
        /* clean up the rank too */
        CFDictionaryRemoveValue(S_ipv4_service_rank_dict, serviceID);
     }
     my_CFRelease(&dict);
+    my_CFRelease(&aggregated_dict);
     my_CFRelease(&routes_data);
     return (changed);
 }
@@ -1822,7 +1958,7 @@ get_ipv6_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
 
 static void
 accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos,
-                      CFMutableArrayRef out_servers)
+                      CFMutableArrayRef out_servers, CFStringRef interface)
 {
     int                        count;
     int                        i;
@@ -1845,13 +1981,15 @@ accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos,
                }
                continue;
            }
+
+           CFRetain(addr);
        }
        else if (cfstring_to_ip6(addr, &ipv6_addr)) {
            /* IPv6 address */
            if ((active_protos & kProtocolFlagsIPv6) == 0
                && !IN6_IS_ADDR_LOOPBACK(&ipv6_addr)) {
                if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
-                   char        ntopbuf[INET6_ADDRSTRLEN];
+                   char        ntopbuf[INET6_ADDRSTRLEN];
 
                    syslog(LOG_NOTICE,
                           "IPMonitor: no IPv6 connectivity, "
@@ -1861,6 +1999,19 @@ accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos,
                }
                continue;
            }
+
+           if ((IN6_IS_ADDR_LINKLOCAL(&ipv6_addr) ||
+                IN6_IS_ADDR_MC_LINKLOCAL(&ipv6_addr))
+               && (interface != NULL)
+               && (CFStringFind(addr, CFSTR("%"), 0).location == kCFNotFound)) {
+               // append interface name to IPv6 link local address
+               addr = CFStringCreateWithFormat(NULL, NULL,
+                                               CFSTR("%@%%%@"),
+                                               addr,
+                                               interface);
+           } else {
+               CFRetain(addr);
+           }
        }
        else {
            /* bad IP address */
@@ -1869,8 +2020,10 @@ accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos,
                  addr);
            continue;
        }
+
        /* DNS server is valid and one we want */
        CFArrayAppendValue(out_servers, addr);
+       CFRelease(addr);
     }
     return;
 }
@@ -1879,9 +2032,12 @@ static void
 merge_dns_servers(CFMutableDictionaryRef new_dict,
                  CFArrayRef state_servers,
                  CFArrayRef setup_servers,
-                 ProtocolFlags active_protos)
+                 Boolean have_setup,
+                 ProtocolFlags active_protos,
+                 CFStringRef interface)
 {
     CFMutableArrayRef  dns_servers;
+    Boolean            have_dns_setup  = FALSE;
 
     if (state_servers == NULL && setup_servers == NULL) {
        /* no DNS servers */
@@ -1891,17 +2047,52 @@ merge_dns_servers(CFMutableDictionaryRef new_dict,
                                       &kCFTypeArrayCallBacks);
     if (setup_servers != NULL) {
        accumulate_dns_servers(setup_servers, active_protos,
-                              dns_servers);
+                              dns_servers, interface);
+       if (CFArrayGetCount(dns_servers) > 0) {
+           have_dns_setup = TRUE;
+       }
     }
     if ((CFArrayGetCount(dns_servers) == 0 || S_append_state)
        && state_servers != NULL) {
        accumulate_dns_servers(state_servers, active_protos,
-                              dns_servers);
+                              dns_servers, NULL);
     }
+
+    /*
+     * Here, we determine whether or not we want all queries for this DNS
+     * configuration to be bound to the associated network interface.
+     *
+     * For dynamically derived network configurations (i.e. from State:)
+     * this would be the preferred option using the argument "Hey, the
+     * server told us to use these servers on this network so let's not
+     * argue".
+     *
+     * But, when a DNS configuration has been provided by the user/admin
+     * via the Network pref pane (i.e. from Setup:) we opt to not force
+     * binding of the outbound queries.  The simplest example why we take
+     * this stance is with a multi-homing configuration.  Consider a system
+     * with one network service associated with "en0" and a second service
+     * associated with "en1".  The "en0" service has been set higher in
+     * the network service order so it would be primary but the user/admin
+     * wants the DNS queries to go to a server only accessible via "en1".
+     * Without this exception we would take the DNS server addresses from
+     * the Network pref pane (for "en0") and have the queries bound to
+     * "en0" where they'd never reach their intended destination (via
+     * "en1").  So, our exception to the rule is that we will not bind
+     * user/admin configurations to any specific network interface.
+     *
+     * We also add an exception to the "follow the dynamically derived
+     * network configuration" path for on-the-fly (no Setup: content)
+     * network services.
+     */
     if (CFArrayGetCount(dns_servers) != 0) {
        CFDictionarySetValue(new_dict,
                             kSCPropNetDNSServerAddresses, dns_servers);
+       if (have_setup && !have_dns_setup) {
+           CFDictionarySetValue(new_dict, DNS_CONFIGURATION_SCOPED_QUERY_KEY, kCFBooleanTrue);
+       }
     }
+
     my_CFRelease(&dns_servers);
     return;
 }
@@ -1914,11 +2105,12 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
     ProtocolFlags              active_protos   = kProtocolFlagsNone;
     boolean_t                  changed         = FALSE;
     CFStringRef                        domain;
+    Boolean                    have_setup      = FALSE;
     CFStringRef                        interface       = NULL;
-    CFDataRef                  ipv4;
+    CFDictionaryRef            ipv4;
     CFDictionaryRef            ipv6;
     int                                i;
-    struct {
+    const struct {
        CFStringRef     key;
        uint32_t        flags;
        Boolean         append;
@@ -1929,45 +2121,49 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
        { kSCPropNetDNSSupplementalMatchOrders,         0,                      TRUE  },
     };
     CFMutableDictionaryRef      new_dict = NULL;
-    CFStringRef                pick_list[] = {
+    const CFStringRef          pick_list[] = {
        kSCPropNetDNSDomainName,
        kSCPropNetDNSOptions,
        kSCPropNetDNSSearchOrder,
        kSCPropNetDNSServerPort,
        kSCPropNetDNSServerTimeout,
     };
+    IPv4RouteListRef           routes = NULL;
 
     if ((state_dict == NULL) && (setup_dict == NULL)) {
        /* there is no DNS content */
        goto done;
     }
 
-    ipv4 = (CFDataRef)service_dict_get(serviceID, kSCEntNetIPv4);
-    if (ipv4 != NULL) {
-       IPv4RouteListRef    routes;
+    ipv4 = service_dict_get(serviceID, kSCEntNetIPv4);
+    routes = ipv4_dict_get_routelist(ipv4);
+
+    if (routes != NULL) {
+       if (get_service_setup_entity(info, serviceID, kSCEntNetIPv4) != NULL) {
+           have_setup = TRUE;
+       }
 
        active_protos |= kProtocolFlagsIPv4;
 
-       routes = (IPv4RouteListRef)CFDataGetBytePtr(ipv4);
-       if (routes->count > 0) {
-           interface = CFStringCreateWithCString(NULL,
-                                                 routes->list[0].ifname,
-                                                 kCFStringEncodingASCII);
-       }
+       interface = ipv4_dict_get_ifname(ipv4);
     }
 
     ipv6 = service_dict_get(serviceID, kSCEntNetIPv6);
     if (ipv6 != NULL) {
+       if (!have_setup &&
+           get_service_setup_entity(info, serviceID, kSCEntNetIPv6) != NULL) {
+           have_setup = TRUE;
+       }
+
        active_protos |= kProtocolFlagsIPv6;
 
-       if ((interface == NULL) &&
-           CFDictionaryGetValueIfPresent(ipv6,
-                                         kSCPropInterfaceName,
-                                         (const void **)&interface)) {
-               CFRetain(interface);
+       if (interface == NULL) {
+           interface = CFDictionaryGetValue(ipv6,
+                                            kSCPropInterfaceName);
        }
     }
 
+
     if (active_protos == kProtocolFlagsNone) {
        /* there is no IPv4 nor IPv6 */
        if (state_dict == NULL) {
@@ -1987,7 +2183,9 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
                          my_CFDictionaryGetArray(state_dict,
                                                  kSCPropNetDNSServerAddresses),
                          NULL,
-                         kProtocolFlagsIPv4 | kProtocolFlagsIPv6);
+                         FALSE,
+                         kProtocolFlagsIPv4 | kProtocolFlagsIPv6,
+                         NULL);
     }
     else {
        merge_dns_servers(new_dict,
@@ -1995,7 +2193,9 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
                                                  kSCPropNetDNSServerAddresses),
                          my_CFDictionaryGetArray(setup_dict,
                                                  kSCPropNetDNSServerAddresses),
-                         active_protos);
+                         have_setup,
+                         active_protos,
+                         interface);
     }
 
     for (i = 0; i < sizeof(merge_list)/sizeof(merge_list[0]); i++) {
@@ -2063,7 +2263,6 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
  done:
     changed = service_dict_set(serviceID, kSCEntNetDNS, new_dict);
     my_CFRelease(&new_dict);
-    my_CFRelease(&interface);
     return (changed);
 }
 
@@ -2078,7 +2277,7 @@ merge_dict(const void *key, const void *value, void *context)
 
 #define        PROXY_AUTO_DISCOVERY_URL        252
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 wpadURL_dhcp(CFDictionaryRef dhcp_options)
 {
     CFStringRef        urlString       = NULL;
@@ -2117,7 +2316,7 @@ wpadURL_dhcp(CFDictionaryRef dhcp_options)
     return urlString;
 }
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 wpadURL_dns(void)
 {
     CFURLRef   url;
@@ -2142,10 +2341,10 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
     ProtocolFlags              active_protos   = kProtocolFlagsNone;
     boolean_t                  changed         = FALSE;
     CFStringRef                        interface       = NULL;
-    CFDataRef                  ipv4;
+    CFDictionaryRef            ipv4;
     CFDictionaryRef            ipv6;
     CFMutableDictionaryRef     new_dict        = NULL;
-    struct {
+    const struct {
        CFStringRef     key;
        uint32_t        flags;
        Boolean         append;
@@ -2153,7 +2352,7 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
        { kSCPropNetProxiesSupplementalMatchDomains,    ALLOW_EMPTY_STRING,     TRUE  },
        { kSCPropNetProxiesSupplementalMatchOrders,     0,                      TRUE  },
     };
-    struct {
+    const struct {
            CFStringRef key1;   /* an "enable" key */
            CFStringRef key2;
            CFStringRef key3;
@@ -2171,36 +2370,30 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
              NULL,
              NULL, }
     };
+    IPv4RouteListRef           routes          = NULL;
 
     if ((state_dict == NULL) && (setup_dict == NULL)) {
        /* there is no proxy content */
        goto done;
     }
 
-    ipv4 = (CFDataRef)service_dict_get(serviceID, kSCEntNetIPv4);
-    if (ipv4 != NULL) {
-       IPv4RouteListRef    routes;
+    ipv4 = service_dict_get(serviceID, kSCEntNetIPv4);
+    routes = ipv4_dict_get_routelist(ipv4);
 
+    if (routes != NULL) {
        active_protos |= kProtocolFlagsIPv4;
 
-       routes = (IPv4RouteListRef)CFDataGetBytePtr(ipv4);
-       if (routes->count > 0) {
-           interface = CFStringCreateWithCString(NULL,
-                                                 routes->list[0].ifname,
-                                                 kCFStringEncodingASCII);
-       }
+       interface = ipv4_dict_get_ifname(ipv4);
     }
 
     ipv6 = service_dict_get(serviceID, kSCEntNetIPv6);
     if (ipv6 != NULL) {
        active_protos |= kProtocolFlagsIPv6;
 
-       if ((interface == NULL) &&
-           CFDictionaryGetValueIfPresent(ipv6,
-                                         kSCPropInterfaceName,
-                                         (const void **)&interface)) {
-               CFRetain(interface);
-           }
+       if (interface == NULL) {
+           interface = CFDictionaryGetValue(ipv6,
+                                            kSCPropInterfaceName);
+       }
     }
 
     if (active_protos == kProtocolFlagsNone) {
@@ -2385,7 +2578,6 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
  done:
     changed = service_dict_set(serviceID, kSCEntNetProxies, new_dict);
     my_CFRelease(&new_dict);
-    my_CFRelease(&interface);
     return (changed);
 }
 
@@ -2397,7 +2589,7 @@ get_smb_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
     boolean_t                  changed = FALSE;
     int                                i;
     CFMutableDictionaryRef      new_dict = NULL;
-    CFStringRef                        pick_list[] = {
+    const CFStringRef          pick_list[] = {
        kSCPropNetSMBNetBIOSName,
        kSCPropNetSMBNetBIOSNodeType,
 #ifdef ADD_NETBIOS_SCOPE
@@ -2447,9 +2639,33 @@ get_smb_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
 }
 #endif /* !TARGET_OS_IPHONE */
 
+static CFStringRef
+services_info_get_interface(CFDictionaryRef services_info,
+                           CFStringRef serviceID)
+{
+    CFStringRef                interface = NULL;
+    CFDictionaryRef    ipv4_dict;
+
+    ipv4_dict = get_service_state_entity(services_info, serviceID,
+                                        kSCEntNetIPv4);
+    if (isA_CFDictionary(ipv4_dict) != NULL) {
+       interface = CFDictionaryGetValue(ipv4_dict, kSCPropInterfaceName);
+    }
+    else {
+       CFDictionaryRef         ipv6_dict;
+
+       ipv6_dict = get_service_state_entity(services_info, serviceID,
+                                            kSCEntNetIPv6);
+       if (isA_CFDictionary(ipv6_dict) != NULL) {
+           interface = CFDictionaryGetValue(ipv6_dict, kSCPropInterfaceName);
+       }
+    }
+    return (interface);
+}
+
 static boolean_t
 get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options,
-                CFDictionaryRef setup_options, CFDictionaryRef info)
+                CFDictionaryRef setup_options, CFDictionaryRef services_info)
 {
     boolean_t                  changed         = FALSE;
     CFMutableDictionaryRef      new_dict       = NULL;
@@ -2461,7 +2677,11 @@ get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options,
     /*
      * Check "PrimaryRank" setting
      *
-     * Note: Rank Never > Rank Last > Rank First > Rank None
+     * Note 1: Rank setting in setup/state option overwrites the
+     *         Rank setting in interface
+     * Within each rank setting, the following precedence is defined:
+     *
+     * Note 2: Rank Never > Rank Last > Rank First > Rank None
      */
     if (isA_CFDictionary(setup_options)) {
        setup_rank = CFDictionaryGetValue(setup_options, kSCPropNetServicePrimaryRank);
@@ -2485,6 +2705,25 @@ get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options,
        new_rank = kSCValNetServicePrimaryRankFirst;
     }
 
+    /* This corresponds to Note 1 */
+    if (setup_rank == NULL && state_rank == NULL) {
+       /* Fetch the interface associated with the service */
+       CFStringRef interface;
+
+       interface = services_info_get_interface(services_info, serviceID);
+
+       /* Get the rank on that interface */
+       if (interface != NULL) {
+           new_rank = CFDictionaryGetValue(S_if_rank_dict, interface);
+           if (S_IPMonitor_debug & kDebugFlag1) {
+               SCLog(TRUE, LOG_NOTICE,
+                     CFSTR("serviceID %@ interface %@ rank = %@"),
+                     serviceID, interface,
+                     (new_rank != NULL) ? new_rank : CFSTR("<none>"));
+           }
+       }
+    }
+
     if (new_rank != NULL) {
        new_dict = CFDictionaryCreateMutable(NULL, 0,
                                             &kCFTypeDictionaryKeyCallBacks,
@@ -2497,6 +2736,83 @@ get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options,
     return (changed);
 }
 
+static CFStringRef
+if_rank_key_copy(CFStringRef ifname)
+{
+    return (SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+                                                         kSCDynamicStoreDomainState,
+                                                         ifname,
+                                                         kSCEntNetService));
+}
+
+static void
+if_rank_set(CFStringRef ifname, CFDictionaryRef rank_dict)
+{
+    CFStringRef                rank = NULL;
+
+    if (isA_CFDictionary(rank_dict) != NULL) {
+       rank = CFDictionaryGetValue(rank_dict, kSCPropNetServicePrimaryRank);
+       rank = isA_CFString(rank);
+    }
+
+    /* specific rank is asserted */
+    if (rank != NULL) {
+       if (S_IPMonitor_debug & kDebugFlag1) {
+           SCLog(TRUE, LOG_NOTICE, CFSTR("Interface %@ asserted rank %@"),
+                 ifname, rank);
+       }
+       CFDictionarySetValue(S_if_rank_dict, ifname, rank);
+    } else {
+       if (S_IPMonitor_debug & kDebugFlag1) {
+           SCLog(TRUE, LOG_NOTICE, CFSTR("Interface %@ removed rank."),
+                 ifname);
+       }
+       CFDictionaryRemoveValue(S_if_rank_dict, ifname);
+    }
+    return;
+}
+
+static void
+if_rank_apply(const void * key, const void * value, void * context)
+{
+    CFStringRef                ifname;
+    CFDictionaryRef    rank_dict = (CFDictionaryRef)value;
+
+    /* State:/Network/Interface/<ifname>/Service, <ifname> is at index 3 */
+    ifname = my_CFStringCopyComponent(key, CFSTR("/"), 3);
+    if (ifname != NULL) {
+       if_rank_set(ifname, rank_dict);
+       CFRelease(ifname);
+    }
+    return;
+}
+
+static void
+if_rank_dict_init(void)
+{
+    CFDictionaryRef    info;
+    CFStringRef                pattern;
+    CFArrayRef         patterns;
+
+    S_if_rank_dict
+       = CFDictionaryCreateMutable(NULL, 0,
+                                   &kCFTypeDictionaryKeyCallBacks,
+                                   &kCFTypeDictionaryValueCallBacks);
+    pattern = if_rank_key_copy(kSCCompAnyRegex);
+    patterns = CFArrayCreate(NULL,
+                            (const void **)&pattern, 1,
+                            &kCFTypeArrayCallBacks);
+    CFRelease(pattern);
+    info = SCDynamicStoreCopyMultiple(S_session, NULL, patterns);
+    CFRelease(patterns);
+    if (info != NULL) {
+       CFDictionaryApplyFunction(info, if_rank_apply, NULL);
+       CFRelease(info);
+    }
+    return;
+
+}
+
 static void
 add_service_keys(CFStringRef serviceID, CFMutableArrayRef keys, CFMutableArrayRef patterns)
 {
@@ -2532,11 +2848,13 @@ add_service_keys(CFStringRef serviceID, CFMutableArrayRef keys, CFMutableArrayRe
 }
 
 static CFDictionaryRef
-services_info_copy(SCDynamicStoreRef session, CFArrayRef service_list)
+services_info_copy(SCDynamicStoreRef session, CFArrayRef service_list,
+                  CFArrayRef if_rank_list)
 {
     int                        count;
     CFMutableArrayRef  get_keys;
     CFMutableArrayRef  get_patterns;
+    int                        if_count;
     CFDictionaryRef    info;
     int                        s;
 
@@ -2554,6 +2872,17 @@ services_info_copy(SCDynamicStoreRef session, CFArrayRef service_list)
        add_service_keys(serviceID, get_keys, get_patterns);
     }
 
+    if_count = (if_rank_list != NULL)
+              ? CFArrayGetCount(if_rank_list) : 0;
+    for (s = 0; s < if_count; s++) {
+       CFStringRef     ifname = CFArrayGetValueAtIndex(if_rank_list, s);
+       CFStringRef     key;
+
+       key = if_rank_key_copy(ifname);
+       CFArrayAppendValue(get_keys, key);
+       CFRelease(key);
+    }
+
     info = SCDynamicStoreCopyMultiple(session, get_keys, get_patterns);
     my_CFRelease(&get_keys);
     my_CFRelease(&get_patterns);
@@ -2630,7 +2959,7 @@ ipv4_route(int sockfd,
     else {
        rtmsg.hdr.rtm_flags = RTF_UP | RTF_CLONING | RTF_STATIC;
     }
-    if ((flags & kRouteWantScopedFlag) != 0) {
+    if ((flags & kRouteIsScopedFlag) != 0) {
 #ifdef RTF_IFSCOPE
        if (!S_scopedroute) {
            return (0);
@@ -2720,7 +3049,9 @@ ipv6_route(int cmd, struct in6_addr gateway, struct in6_addr netaddr,
 
     default_route = (bcmp(&zeroes, &netaddr, sizeof(netaddr)) == 0);
 
-    if (IN6_IS_ADDR_LINKLOCAL(&gateway) && ifname != NULL) {
+    if ((IN6_IS_ADDR_LINKLOCAL(&gateway) ||
+        IN6_IS_ADDR_MC_LINKLOCAL(&gateway)) &&
+       (ifname != NULL)) {
        unsigned int    index = if_nametoindex(ifname);
 
        /* add the scope id to the link local address */
@@ -2806,7 +3137,7 @@ ipv6_default_route_add(struct in6_addr router, char * ifname,
                       boolean_t is_direct)
 {
     if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
-       char    ntopbuf[INET6_ADDRSTRLEN];
+       char    ntopbuf[INET6_ADDRSTRLEN];
 
        SCLog(TRUE, LOG_NOTICE,
              CFSTR("IPMonitor: IPv6 route add default"
@@ -2987,13 +3318,12 @@ router_is_our_ipv6_address(CFStringRef router, CFArrayRef addr_list)
 static IPv4RouteListRef
 service_dict_get_ipv4_routelist(CFDictionaryRef service_dict)
 {
-    CFDataRef          data;
+    CFDictionaryRef    dict;
     IPv4RouteListRef   routes = NULL;
 
-    data = (CFDataRef)CFDictionaryGetValue(service_dict, kSCEntNetIPv4);
-    if (data != NULL) {
-       routes = (IPv4RouteListRef)CFDataGetBytePtr(data);
-    }
+    dict = CFDictionaryGetValue(service_dict, kSCEntNetIPv4);
+
+    routes = ipv4_dict_get_routelist(dict);
     return (routes);
 }
 
@@ -3013,8 +3343,7 @@ ipv4_route_gateway(int sockfd, int cmd, char * ifn_p,
     mask.s_addr = htonl(INADDR_BROADCAST);
     return (ipv4_route(sockfd, cmd, def_route->ifa,
                       def_route->gateway, mask, ifn_p, def_route->ifindex,
-                      def_route->ifa,
-                      (def_route->flags & kRouteWantScopedFlag)));
+                      def_route->ifa, def_route->flags));
 }
 
 /*
@@ -3225,7 +3554,7 @@ update_ipv4(CFStringRef           primary,
 }
 
 static void
-update_ipv6(CFDictionaryRef    service_info,
+update_ipv6(CFDictionaryRef    services_info,
            CFStringRef         primary,
            keyChangeListRef    keys)
 {
@@ -3306,7 +3635,7 @@ update_ipv6(CFDictionaryRef       service_info,
 }
 
 static void
-update_dns(CFDictionaryRef     service_info,
+update_dns(CFDictionaryRef     services_info,
           CFStringRef          primary,
           keyChangeListRef     keys)
 {
@@ -3339,6 +3668,7 @@ update_dns(CFDictionaryRef        service_info,
        CFDictionaryRemoveValue(new_dict, kSCPropInterfaceName);
        CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSupplementalMatchDomains);
        CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSupplementalMatchOrders);
+       CFDictionaryRemoveValue(new_dict, DNS_CONFIGURATION_SCOPED_QUERY_KEY);
        keyChangeListSetValue(keys, S_state_global_dns, new_dict);
        CFRelease(new_dict);
     }
@@ -3346,17 +3676,18 @@ update_dns(CFDictionaryRef      service_info,
 }
 
 static void
-update_dnsinfo(CFDictionaryRef service_info,
+update_dnsinfo(CFDictionaryRef services_info,
               CFStringRef      primary,
               keyChangeListRef keys,
               CFArrayRef       service_order)
 {
+    Boolean            changed;
     CFDictionaryRef    dict    = NULL;
     CFArrayRef         multicastResolvers;
     CFArrayRef         privateResolvers;
 
-    multicastResolvers = CFDictionaryGetValue(service_info, S_multicast_resolvers);
-    privateResolvers   = CFDictionaryGetValue(service_info, S_private_resolvers);
+    multicastResolvers = CFDictionaryGetValue(services_info, S_multicast_resolvers);
+    privateResolvers   = CFDictionaryGetValue(services_info, S_private_resolvers);
 
     if (primary != NULL) {
        CFDictionaryRef service_dict;
@@ -3367,17 +3698,19 @@ update_dnsinfo(CFDictionaryRef  service_info,
        }
     }
 
-    dns_configuration_set(dict,
-                         S_service_state_dict,
-                         service_order,
-                         multicastResolvers,
-                         privateResolvers);
-    keyChangeListNotifyKey(keys, S_state_global_dns);
+    changed = dns_configuration_set(dict,
+                                   S_service_state_dict,
+                                   service_order,
+                                   multicastResolvers,
+                                   privateResolvers);
+    if (changed) {
+       keyChangeListNotifyKey(keys, S_state_global_dns);
+    }
     return;
 }
 
 static void
-update_proxies(CFDictionaryRef service_info,
+update_proxies(CFDictionaryRef services_info,
               CFStringRef      primary,
               keyChangeListRef keys,
               CFArrayRef       service_order)
@@ -3409,7 +3742,7 @@ update_proxies(CFDictionaryRef    service_info,
 
 #if    !TARGET_OS_IPHONE
 static void
-update_smb(CFDictionaryRef     service_info,
+update_smb(CFDictionaryRef     services_info,
           CFStringRef          primary,
           keyChangeListRef     keys)
 {
@@ -3438,7 +3771,7 @@ static Rank
 get_service_rank(CFArrayRef order, int n_order, CFStringRef serviceID)
 {
     CFIndex            i;
-    Rank               rank = kRankLast;
+    Rank               rank = kRankIndexMask;
 
     if (serviceID != NULL && order != NULL && n_order > 0) {
        for (i = 0; i < n_order; i++) {
@@ -3468,7 +3801,7 @@ static Rank
 rank_dict_get_service_rank(CFDictionaryRef rank_dict, CFStringRef serviceID)
 {
     CFNumberRef                rank;
-    Rank               rank_val = kRankLast;
+    Rank               rank_val = RankMake(kRankIndexMask, kRankAssertionDefault);
 
     rank = CFDictionaryGetValue(rank_dict, serviceID);
     if (rank != NULL) {
@@ -3503,8 +3836,7 @@ typedef struct election_info {
     int                        n_order;
     CFStringRef                serviceID;
     CFDictionaryRef    service_dict;
-    Rank               service_rank;
-    boolean_t          choose_last;
+    Rank               rank;
 } election_info_t;
 
 typedef boolean_t election_func_t(void * context, election_info_t * info);
@@ -3519,37 +3851,39 @@ typedef boolean_t election_func_t(void * context, election_info_t * info);
 static boolean_t
 elect_ipv4(void * context, election_info_t * info)
 {
+    Rank               primary_rank;
     IPv4RouteListRef * routes_p = (IPv4RouteListRef *)context;
     IPv4RouteListRef   service_routes;
 
     service_routes = service_dict_get_ipv4_routelist(info->service_dict);
+
+    info->rank = get_service_rank(info->order, info->n_order,
+                                   info->serviceID);
+
     if (service_routes == NULL) {
        return (FALSE);
     }
-    if ((service_routes->list->flags & kRouteChooseFirstFlag) != 0) {
-       info->service_rank = kRankFirst;
-    }
-    else if (S_ppp_override_primary
+
+    primary_rank = RANK_ASSERTION_MASK(service_routes->list->rank);
+
+    if (S_ppp_override_primary
             && (strncmp(PPP_PREFIX, service_routes->list->ifname,
                         sizeof(PPP_PREFIX) - 1) == 0)) {
        /* PPP override: make ppp* look the best */
        /* Hack: should use interface type, not interface name */
-       info->service_rank = kRankFirst;
-    }
-    else {
-       info->service_rank = get_service_rank(info->order, info->n_order,
-                                             info->serviceID);
-       if ((service_routes->list->flags & kRouteChooseLastFlag) != 0) {
-           info->choose_last = TRUE;
-       }
+       primary_rank = kRankAssertionFirst;
     }
+
+    info->rank = RankMake(info->rank, primary_rank);
+
     if (routes_p != NULL) {
        *routes_p = IPv4RouteListAddRouteList(*routes_p,
                                              info->n_services * 3,
                                              service_routes,
-                                             info->service_rank);
+                                             info->rank);
     }
-    if ((service_routes->list->flags & kRouteChooseNeverFlag) != 0) {
+
+    if (primary_rank == kRankAssertionNever) {
        /* never elect as primary */
        return (FALSE);
     }
@@ -3560,66 +3894,243 @@ elect_ipv4(void * context, election_info_t * info)
     }
 
     rank_dict_set_service_rank(S_ipv4_service_rank_dict,
-                              info->serviceID, info->service_rank);
+                              info->serviceID, info->rank);
     return (TRUE);
 }
 
-static boolean_t
-elect_ipv6(void * context, election_info_t * info)
+static void
+IPv6RankedListInsertE(IPv6RankedListRef list, IPv6RankedERef e)
 {
-    CFStringRef                if_name;
-    CFStringRef                primaryRank     = NULL;
-    CFDictionaryRef    proto_dict;
-    CFStringRef                router;
-    CFDictionaryRef    service_options;
+    int        idx                 = 0;
+    int elems_to_be_moved   = 0;
+
+    if (list == NULL) return;
+
+    for (idx = 0; idx < list->count; idx++) {
+       if ((e->rank < list->elem[idx].rank)) {
+           break;
+       }
+    }
+
+    if ((S_IPMonitor_debug & kDebugFlag2) != 0) {
+       SCLog(TRUE, LOG_NOTICE,
+             CFSTR("IPv6RankedListInsertE: %s flags 0x%x at index %d with rank %u."),
+             e->ifname, e->flags, idx, e->rank);
+    }
+
+    elems_to_be_moved = list->count - idx;
+    if (elems_to_be_moved > 0) {
+       bcopy((void*) &list->elem[idx], (void*) &list->elem[idx+1],
+             elems_to_be_moved * sizeof(*e));
+    }
+
+    bcopy((void*) e, (void*) &list->elem[idx], sizeof(*e));
+    list->count++;
+    return;
+}
+
+static boolean_t
+elect_ipv6(void * context, election_info_t * info)
+{
+    CFStringRef                if_name;
+    CFStringRef                primaryRankStr  = NULL;
+    CFDictionaryRef    proto_dict;
+    CFStringRef                router;
+    CFDictionaryRef    service_options;
+    IPv6RankedListRef  list = (IPv6RankedListRef) context;
+    IPv6RankedE                elem;
+    CFDictionaryRef    dns_dict = NULL;
+    Rank               primary_rank = kRankAssertionDefault;
+
+    memset((void *)&elem, 0, sizeof(elem));
+
+    info->rank = get_service_rank(info->order, info->n_order, info->serviceID);
 
     proto_dict = CFDictionaryGetValue(info->service_dict, kSCEntNetIPv6);
     if (proto_dict == NULL) {
        return (FALSE);
     }
-    service_options = service_dict_get(info->serviceID, kSCEntNetService);
-    if (service_options != NULL) {
-       primaryRank = CFDictionaryGetValue(service_options, kSCPropNetServicePrimaryRank);
-       if ((primaryRank != NULL)
-           && CFEqual(primaryRank, kSCValNetServicePrimaryRankNever)) {
-           return (FALSE);
-       }
-    }
     if_name = CFDictionaryGetValue(proto_dict, kSCPropInterfaceName);
-    if (if_name != NULL && CFEqual(if_name, CFSTR("lo0"))) {
-       /* never elect as primary */
+    if (if_name == NULL) {
+       /* we need an interface name */
+       return (FALSE);
+    }
+    if (CFEqual(if_name, CFSTR("lo0"))) {
+       /* don't ever elect loopback */
        return (FALSE);
     }
+    CFStringGetCString(if_name, elem.ifname,
+                      sizeof(elem.ifname),
+                      kCFStringEncodingASCII);
     router = CFDictionaryGetValue(proto_dict,
                                  kSCPropNetIPv6Router);
     if (router == NULL) {
-       info->choose_last = TRUE;
-       info->service_rank = kRankLast;
+       /* can't become primary without a router */
+       return (FALSE);
     }
-    else if ((primaryRank != NULL)
-            && CFEqual(primaryRank, kSCValNetServicePrimaryRankFirst)) {
-       info->service_rank = kRankFirst;
+
+    dns_dict = service_dict_get(info->serviceID, kSCEntNetDNS);
+    if (dns_dict != NULL) {
+       elem.flags |= NWI_IFSTATE_FLAGS_HAS_DNS;
     }
-    else if (get_override_primary(proto_dict)) {
-       info->service_rank = kRankFirst;
+
+    service_options = service_dict_get(info->serviceID, kSCEntNetService);
+    if (service_options != NULL) {
+       primaryRankStr = CFDictionaryGetValue(service_options, kSCPropNetServicePrimaryRank);
+       if (primaryRankStr != NULL) {
+           primary_rank = PrimaryRankGetRankAssertion(primaryRankStr);
+       }
+       if (primary_rank == kRankAssertionNever) {
+           elem.flags |= NWI_IFSTATE_FLAGS_NOT_IN_LIST;
+           elem.rank = RankMake(info->rank, primary_rank);
+           IPv6RankedListInsertE(list, &elem);
+           return (FALSE);
+       }
+    }
+
+    if (get_override_primary(proto_dict)) {
+       primary_rank = kRankAssertionFirst;
     }
     else if (S_ppp_override_primary
-            && if_name != NULL
             && CFStringHasPrefix(if_name, CFSTR(PPP_PREFIX))) {
        /* PPP override: make ppp* look the best */
        /* Hack: should use interface type, not interface name */
-       info->service_rank = kRankFirst;
-    }
-    else {
-       info->service_rank = get_service_rank(info->order, info->n_order,
-                                             info->serviceID);
+       primary_rank = kRankAssertionFirst;
     }
 
+    elem.rank = RankMake(info->rank, primary_rank);
+    info->rank = RankMake(info->rank, primary_rank);
+
+    (void)cfstring_to_ip6(router, &elem.iaddr6);
+
+    IPv6RankedListInsertE(list, &elem);
     rank_dict_set_service_rank(S_ipv6_service_rank_dict,
-                              info->serviceID, info->service_rank);
+                              info->serviceID, info->rank);
     return (TRUE);
 }
 
+static void
+update_nwi_state_ipv6(nwi_state_t state, IPv6RankedListRef list)
+{
+    int idx;
+
+    if (state == NULL) {
+       return;
+    }
+
+    /* A null list indicates to clear the ifstates */
+    nwi_state_clear(state, AF_INET6);
+
+    if (list == NULL) {
+       return;
+    }
+
+    for (idx = 0 ; idx < list->count; idx++) {
+       if ((S_IPMonitor_debug & kDebugFlag2) != 0) {
+           char        ntopbuf[INET6_ADDRSTRLEN];
+
+           inet_ntop(AF_INET6, &list->elem[idx].iaddr6, ntopbuf,
+                     sizeof(ntopbuf));
+
+           SCLog(TRUE, LOG_NOTICE,
+                 CFSTR("Inserting v6 [%s] into list with flags 0x%x"
+                       " with rank %lu ipv6 addr %s"),
+                       list->elem[idx].ifname, list->elem[idx].flags,
+                       list->elem[idx].rank, ntopbuf);
+       }
+
+       nwi_insert_ifstate(state, list->elem[idx].ifname,
+                          AF_INET6, list->elem[idx].flags,
+                          list->elem[idx].rank,
+                          (void *)&list->elem[idx].iaddr6);
+    }
+    nwi_state_set_last(state, AF_INET6);
+}
+
+static boolean_t
+interface_has_dns(const void * * values, int values_count,
+                 const char * ifname)
+{
+    boolean_t          has_dns = FALSE;
+    int                        i;
+    CFStringRef                ifname_cf;
+
+    ifname_cf = CFStringCreateWithCString(NULL, ifname, kCFStringEncodingASCII);
+    for (i = 0; i < values_count; i++) {
+       CFDictionaryRef         dns_dict;
+
+       dns_dict = CFDictionaryGetValue(values[i], kSCEntNetDNS);
+       if (dns_dict != NULL) {
+           CFStringRef         this_ifname;
+
+           this_ifname = CFDictionaryGetValue(dns_dict, kSCPropInterfaceName);
+           if (this_ifname != NULL
+               && CFEqual(this_ifname, ifname_cf)) {
+               has_dns = TRUE;
+               break;
+           }
+       }
+    }
+    CFRelease(ifname_cf);
+    return (has_dns);
+}
+
+static void
+update_nwi_state_ipv4(nwi_state_t state, IPv4RouteListRef route)
+{
+    int                        idx;
+    IPv4RouteRef       r;
+    const void * *     values;
+    const void *       values_buf[10];
+    int                        values_count;
+
+    if (state == NULL) {
+       return;
+    }
+    nwi_state_clear(state, AF_INET);
+    if (route == NULL) {
+       return;
+    }
+    values_count = CFDictionaryGetCount(S_service_state_dict);
+    if (values_count == 0) {
+       return;
+    }
+    if (values_count <= (sizeof(values_buf) / sizeof(values_buf[0]))) {
+       values = values_buf;
+    }
+    else {
+       values = (const void * *)malloc(sizeof(*values) * values_count);
+    }
+    CFDictionaryGetKeysAndValues(S_service_state_dict,
+                                NULL, (const void * *)values);
+    for (idx = 0, r = route->list; idx < route->count; idx++, r++)  {
+       uint64_t                flags = 0ULL;
+
+       if (r->dest.s_addr != 0) {
+           /* we're done, no more default routes */
+           break;
+       }
+       if (RANK_ASSERTION_MASK(r->rank) == kRankAssertionNever) {
+           flags |= NWI_IFSTATE_FLAGS_NOT_IN_LIST;
+       }
+
+       if (interface_has_dns(values, values_count, r->ifname)) {
+           flags |= NWI_IFSTATE_FLAGS_HAS_DNS;
+       }
+       if ((S_IPMonitor_debug & kDebugFlag2) != 0) {
+           SCLog(TRUE, LOG_NOTICE, CFSTR("Inserting v4 [%s] with flags 0x%x primary_rank %u"),
+                 r->ifname, flags, r->rank);
+       }
+       nwi_insert_ifstate(state, r->ifname, AF_INET, flags, r->rank,
+                          (void *)&r->ifa);
+    }
+    if (values != values_buf) {
+       free(values);
+    }
+    nwi_state_set_last(state, AF_INET);
+    return;
+}
+
 /*
  * Function: elect_new_primary
  * Purpose:
@@ -3638,8 +4149,7 @@ elect_new_primary(election_func_t * elect_func, void * context,
 #define N_KEYS_VALUES_STATIC   10
     void *             keys_values_buf[N_KEYS_VALUES_STATIC * 2];
     CFStringRef                new_primary = NULL;
-    Rank               new_primary_rank = kRankLast;
-    boolean_t          new_primary_choose_last = FALSE;
+    Rank               new_rank = 0;
     void * *           values;
 
     count = CFDictionaryGetCount(S_service_state_dict);
@@ -3657,30 +4167,25 @@ elect_new_primary(election_func_t * elect_func, void * context,
     info.n_services = count;
     info.order = order;
     info.n_order = n_order;
+    new_rank = 0;
     for (i = 0; i < count; i++) {
        boolean_t       found_new_primary = FALSE;
 
        info.serviceID = (CFStringRef)keys[i];
        info.service_dict = (CFDictionaryRef)values[i];
-       info.service_rank = kRankLast;
-       info.choose_last = FALSE;
+       info.rank = kRankAssertionMask;
 
        if ((*elect_func)(context, &info) == FALSE) {
            continue;
        }
-       if (new_primary == NULL) {
-           found_new_primary = TRUE;
-       }
-       else if (info.choose_last == new_primary_choose_last) {
-           found_new_primary = (info.service_rank < new_primary_rank);
-       }
-       else if (new_primary_choose_last) {
+       if (new_primary == NULL
+           || (info.rank < new_rank)) {
            found_new_primary = TRUE;
        }
+
        if (found_new_primary) {
            new_primary = info.serviceID;
-           new_primary_rank = info.service_rank;
-           new_primary_choose_last = info.choose_last;
+           new_rank = info.rank;
        }
     }
     if (new_primary != NULL) {
@@ -3795,27 +4300,285 @@ rank_service_entity(CFDictionaryRef rank_dict, CFStringRef serviceID,
                    CFStringRef entity)
 {
     if (service_dict_get(serviceID, entity) == NULL) {
-       return (kRankLast);
+       return (RankMake(kRankIndexMask, kRankAssertionDefault));
     }
     return (rank_dict_get_service_rank(rank_dict, serviceID));
 }
 
+static __inline__ unsigned int
+IPv6RankedListComputeSize(int n)
+{
+       return (offsetof(IPv6RankedList, elem[n]));
+
+}
+
+static void
+update_interface_rank(CFDictionaryRef services_info, CFStringRef ifname)
+{
+    CFStringRef                if_rank_key;
+    CFDictionaryRef    rank_dict;
+
+    if_rank_key = if_rank_key_copy(ifname);
+    rank_dict = CFDictionaryGetValue(services_info, if_rank_key);
+    CFRelease(if_rank_key);
+    if_rank_set(ifname, rank_dict);
+    return;
+}
+
+static void
+append_serviceIDs_for_interface(CFMutableArrayRef services_changed,
+                               CFStringRef ifname)
+{
+    int                        count;
+    int                        i;
+    void * *           keys;
+#define N_KEYS_VALUES_STATIC    10
+    void *             keys_values_buf[N_KEYS_VALUES_STATIC * 2];
+    void * *           values;
+
+    count = CFDictionaryGetCount(S_service_state_dict);
+    if (count <= N_KEYS_VALUES_STATIC) {
+       keys = keys_values_buf;
+    } else {
+       keys = (void * *)malloc(sizeof(*keys) * count * 2);
+    }
+    values = keys + count;
+    CFDictionaryGetKeysAndValues(S_service_state_dict,
+                                (const void * *)keys,
+                                (const void * *)values);
+
+    for (i = 0; i < count; i++) {
+       CFDictionaryRef         ipv4 = NULL;
+       CFStringRef             interface = NULL;
+       CFStringRef             serviceID;
+       CFDictionaryRef         service_dict;
+
+       serviceID = (CFStringRef)keys[i];
+       service_dict = (CFDictionaryRef)values[i];
+
+       /* check if this is a ipv4 dictionary */
+       ipv4  = CFDictionaryGetValue(service_dict, kSCEntNetIPv4);
+       if (ipv4 != NULL) {
+           interface = ipv4_dict_get_ifname(ipv4);
+           if (interface != NULL && CFEqual(interface, ifname)) {
+               if (S_IPMonitor_debug & kDebugFlag1) {
+                   SCLog(TRUE, LOG_NOTICE, CFSTR("Found ipv4 service %@ on interface %@."),
+                         serviceID, ifname);
+               }
+
+               my_CFArrayAppendUniqueValue(services_changed, serviceID);
+           }
+       } else {
+           CFDictionaryRef     proto_dict;
+
+           /* check if this is a ipv6 dictionary */
+           proto_dict = CFDictionaryGetValue(service_dict, kSCEntNetIPv6);
+           if (proto_dict == NULL) {
+               continue;
+           }
+           interface = CFDictionaryGetValue(proto_dict, kSCPropInterfaceName);
+           if (interface != NULL && CFEqual(interface, ifname)) {
+               if (S_IPMonitor_debug & kDebugFlag1) {
+                   SCLog(TRUE, LOG_NOTICE, CFSTR("Found ipv6 service %@ on interface %@."),
+                         serviceID, ifname);
+               }
+
+               my_CFArrayAppendUniqueValue(services_changed, serviceID);
+           }
+       }
+    }
+
+    if (keys != keys_values_buf) {
+       free(keys);
+    }
+}
+
+static const CFStringRef *statusEntityNames[] = {
+    &kSCEntNetIPSec,
+    &kSCEntNetPPP,
+    &kSCEntNetVPN,
+};
+
+static void
+add_status_keys(CFMutableArrayRef patterns)
+{
+    int            i;
+
+    for (i = 0; i < sizeof(statusEntityNames)/sizeof(statusEntityNames[0]); i++) {
+       CFStringRef     pattern;
+
+       pattern = state_service_key(kSCCompAnyRegex, *statusEntityNames[i]);
+       CFArrayAppendValue(patterns, pattern);
+       CFRelease(pattern);
+    }
+
+    return;
+}
+
+static
+inline
+const char *
+get_changed_str(CFStringRef serviceID, CFStringRef entity, CFDictionaryRef old_dict)
+{
+    CFDictionaryRef new_dict    = NULL;
+
+    if (serviceID != NULL) {
+       new_dict = service_dict_get(serviceID, entity);
+    }
+
+    if (old_dict == NULL) {
+       if (new_dict != NULL) {
+           return "+";
+       }
+    } else {
+       if (new_dict == NULL) {
+           return "-";
+       } else if (!CFEqual(old_dict, new_dict)) {
+           return "!";
+       }
+    }
+    return "";
+}
+
+static CF_RETURNS_RETAINED CFStringRef
+generate_log_changes(nwi_state_t       changes_state,
+                    boolean_t          dns_changed,
+                    boolean_t          dnsinfo_changed,
+                    CFDictionaryRef    old_primary_dns,
+                    boolean_t          proxy_changed,
+                    CFDictionaryRef    old_primary_proxy,
+                    boolean_t          smb_changed,
+                    CFDictionaryRef    old_primary_smb
+                    )
+{
+    int idx;
+    CFMutableStringRef log_output;
+    nwi_ifstate_t scan;
+
+    log_output = CFStringCreateMutable(NULL, 0);
+
+    if (changes_state != NULL) {
+       for (idx = 0; idx < sizeof(nwi_af_list)/sizeof(nwi_af_list[0]); idx++) {
+           CFMutableStringRef changes = NULL;
+           CFMutableStringRef primary_str = NULL;
+
+           scan = nwi_state_get_first_ifstate(changes_state, nwi_af_list[idx]);
+
+           while (scan != NULL) {
+               const char * changed_str;
+
+               changed_str = nwi_ifstate_get_diff_str(scan);
+               if (changed_str != NULL) {
+                   void *              address;
+                   const char *        addr_str;
+                   char                ntopbuf[INET6_ADDRSTRLEN];
+
+                   address = (void *)nwi_ifstate_get_address(scan);
+                   addr_str = inet_ntop(scan->af, address,
+                               ntopbuf, sizeof(ntopbuf));
+
+                   if (primary_str ==  NULL) {
+                       primary_str = CFStringCreateMutable(NULL, 0);
+                       CFStringAppendFormat(primary_str, NULL, CFSTR("%s%s:%s"),
+                                            nwi_ifstate_get_ifname(scan),
+                                            changed_str, addr_str);
+                   } else {
+                       if (changes == NULL) {
+                           changes = CFStringCreateMutable(NULL, 0);
+                       }
+                       CFStringAppendFormat(changes, NULL, CFSTR(", %s"),
+                                            nwi_ifstate_get_ifname(scan));
+                       if (strcmp(changed_str,  "") != 0) {
+                           CFStringAppendFormat(changes, NULL, CFSTR("%s:%s"),
+                                                changed_str, addr_str);
+                       }
+                   }
+               }
+               scan = nwi_ifstate_get_next(scan, scan->af);
+           }
+
+           if (primary_str != NULL) {
+               CFStringAppendFormat(log_output, NULL, CFSTR(" %s(%@"),
+                                    nwi_af_list[idx] == AF_INET ? "v4" : "v6",
+                                    primary_str);
+
+               if (changes != NULL && CFStringGetLength(changes) != 0) {
+                   CFStringAppendFormat(log_output, NULL, CFSTR("%@"),
+                                        changes);
+               }
+               CFStringAppendFormat(log_output, NULL, CFSTR(")"));
+
+               my_CFRelease(&primary_str);
+               my_CFRelease(&changes);
+           }
+       }
+    }
+
+    if (dns_changed || dnsinfo_changed) {
+       const char    *str;
+
+       str = get_changed_str(S_primary_dns, kSCEntNetDNS, old_primary_dns);
+       if ((strcmp(str, "") == 0) && dnsinfo_changed) {
+           str = "*";      // dnsinfo change w/no change to primary
+       }
+       CFStringAppendFormat(log_output, NULL, CFSTR(" DNS%s"), str);
+    } else if (S_primary_dns != NULL){
+       CFStringAppendFormat(log_output, NULL, CFSTR(" DNS"));
+    }
+
+    if (proxy_changed) {
+       const char    *str;
+
+       str = get_changed_str(S_primary_proxies, kSCEntNetProxies, old_primary_proxy);
+       CFStringAppendFormat(log_output, NULL, CFSTR(" Proxy%s"), str);
+    } else if (S_primary_proxies != NULL) {
+       CFStringAppendFormat(log_output, NULL, CFSTR(" Proxy"));
+    }
+
+#if    !TARGET_OS_IPHONE
+    if (smb_changed) {
+       const char    *str;
+
+       str = get_changed_str(S_primary_smb, kSCEntNetSMB, old_primary_smb);
+       CFStringAppendFormat(log_output, NULL, CFSTR(" SMB%s"), str);
+    } else if (S_primary_smb != NULL) {
+       CFStringAppendFormat(log_output, NULL, CFSTR(" SMB"));
+    }
+#endif // !TARGET_OS_IPHONE
+
+    return log_output;
+}
+
 static void
 IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
                void * not_used)
 {
     CFIndex            count;
-    boolean_t          dnsinfo_changed = FALSE;
-    boolean_t          global_ipv4_changed = FALSE;
-    boolean_t          global_ipv6_changed = FALSE;
+    nwi_state_t                changes_state           = NULL;
+    boolean_t          dns_changed             = FALSE;
+    boolean_t          dnsinfo_changed         = FALSE;
+    boolean_t          global_ipv4_changed     = FALSE;
+    boolean_t          global_ipv6_changed     = FALSE;
     int                        i;
+    CFMutableArrayRef  if_rank_changes         = NULL;
     keyChangeList      keys;
     CFIndex            n;
-    int                        n_service_order = 0;
-    boolean_t          proxies_changed = FALSE;
+    CFStringRef                network_change_msg;
+    int                        n_services;
+    int                        n_service_order         = 0;
+    nwi_state_t                old_nwi_state           = NULL;
+    CFDictionaryRef    old_primary_dns         = NULL;
+    CFDictionaryRef    old_primary_proxy       = NULL;
+#if    !TARGET_OS_IPHONE
+    CFDictionaryRef    old_primary_smb         = NULL;
+#endif // !TARGET_OS_IPHONE
+    boolean_t          proxies_changed         = FALSE;
     CFArrayRef         service_order;
-    CFMutableArrayRef  service_changes = NULL;
-    CFDictionaryRef    services_info = NULL;
+    CFMutableArrayRef  service_changes         = NULL;
+    CFDictionaryRef    services_info           = NULL;
+#if    !TARGET_OS_IPHONE
+    boolean_t          smb_changed             = FALSE;
+#endif // !TARGET_OS_IPHONE
 
     count = CFArrayGetCount(changed_keys);
     if (count == 0) {
@@ -3827,9 +4590,33 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
              CFSTR("IPMonitor: changes %@ (%d)"), changed_keys, count);
     }
 
+    if (S_primary_dns != NULL) {
+       old_primary_dns = service_dict_get(S_primary_dns, kSCEntNetDNS);
+       if (old_primary_dns != NULL) {
+           old_primary_dns = CFDictionaryCreateCopy(NULL, old_primary_dns);
+       }
+    }
+
+    if (S_primary_proxies != NULL) {
+       old_primary_proxy = service_dict_get(S_primary_proxies, kSCEntNetProxies);
+       if (old_primary_proxy != NULL) {
+           old_primary_proxy = CFDictionaryCreateCopy(NULL, old_primary_proxy);
+       }
+    }
+
+#if    !TARGET_OS_IPHONE
+    if (S_primary_smb != NULL) {
+       old_primary_smb = service_dict_get(S_primary_smb, kSCEntNetSMB);
+       if (old_primary_smb != NULL) {
+           old_primary_smb = CFDictionaryCreateCopy(NULL, old_primary_smb);
+       }
+    }
+#endif // !TARGET_OS_IPHONE
+
     keyChangeListInit(&keys);
     service_changes = CFArrayCreateMutable(NULL, 0,
                                           &kCFTypeArrayCallBacks);
+
     for (i = 0; i < count; i++) {
        CFStringRef     change = CFArrayGetValueAtIndex(changed_keys, i);
        if (CFEqual(change, S_setup_global_ipv4)) {
@@ -3848,11 +4635,24 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
        }
 #endif /* !TARGET_OS_IPHONE */
        else if (CFStringHasPrefix(change, S_state_service_prefix)) {
-           CFStringRef serviceID = parse_component(change,
-                                                   S_state_service_prefix);
-           if (serviceID) {
-               my_CFArrayAppendUniqueValue(service_changes, serviceID);
-               CFRelease(serviceID);
+           int         i;
+           boolean_t   status_changed = FALSE;
+
+           for (i = 0; i < sizeof(statusEntityNames)/sizeof(statusEntityNames[0]); i++) {
+               if (CFStringHasSuffix(change, *statusEntityNames[i])) {
+                   status_changed = TRUE;
+                   dnsinfo_changed = TRUE;
+                   break;
+               }
+           }
+
+           if (!status_changed) {
+               CFStringRef serviceID = parse_component(change,
+                                                       S_state_service_prefix);
+               if (serviceID) {
+                   my_CFArrayAppendUniqueValue(service_changes, serviceID);
+                   CFRelease(serviceID);
+               }
            }
        }
        else if (CFStringHasPrefix(change, S_setup_service_prefix)) {
@@ -3863,10 +4663,37 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
                CFRelease(serviceID);
            }
        }
+       else if (CFStringHasSuffix(change, kSCEntNetService)) {
+           CFStringRef ifname = my_CFStringCopyComponent(change, CFSTR("/"), 3);
+
+           if (ifname != NULL) {
+               if (if_rank_changes == NULL) {
+                   if_rank_changes = CFArrayCreateMutable(NULL, 0,
+                                                          &kCFTypeArrayCallBacks);
+               }
+               my_CFArrayAppendUniqueValue(if_rank_changes, ifname);
+               CFRelease(ifname);
+           }
+       }
+    }
+
+    /* determine which serviceIDs are impacted by the interface rank changes */
+    if (if_rank_changes != NULL) {
+       n = CFArrayGetCount(if_rank_changes);
+       for (i = 0; i < n; i++) {
+           CFStringRef ifname = CFArrayGetValueAtIndex(if_rank_changes, i);
+
+           if (S_IPMonitor_debug & kDebugFlag1) {
+               SCLog(TRUE, LOG_NOTICE, CFSTR("Interface rank changed %@"),
+                     ifname);
+           }
+           append_serviceIDs_for_interface(service_changes, ifname);
+       }
     }
 
     /* grab a snapshot of everything we need */
-    services_info = services_info_copy(session, service_changes);
+    services_info = services_info_copy(session, service_changes,
+                                      if_rank_changes);
     service_order = service_order_get(services_info);
     if (service_order != NULL) {
        n_service_order = CFArrayGetCount(service_order);
@@ -3875,6 +4702,14 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
                  CFSTR("IPMonitor: service_order %@ "), service_order);
        }
     }
+
+    if (if_rank_changes != NULL) {
+       for (i = 0; i < n; i++) {
+           CFStringRef ifname = CFArrayGetValueAtIndex(if_rank_changes, i);
+           update_interface_rank(services_info, ifname);
+       }
+    }
+
     n = CFArrayGetCount(service_changes);
     for (i = 0; i < n; i++) {
        uint32_t        changes;
@@ -3917,9 +4752,14 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
 #endif /* !TARGET_OS_IPHONE */
     }
 
-    if (global_ipv4_changed) {
+    /* ensure S_nwi_state can hold as many services as we have currently */
+    n_services = CFDictionaryGetCount(S_service_state_dict);
+    old_nwi_state = nwi_state_copy_priv(S_nwi_state);
+    S_nwi_state = nwi_state_new(S_nwi_state, n_services);
+
+    if (global_ipv4_changed || dnsinfo_changed) {
        IPv4RouteListRef        new_routelist = NULL;
-       CFStringRef             new_primary;
+       CFStringRef             new_primary;
 
        if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
            SCLog(TRUE, LOG_NOTICE,
@@ -3927,21 +4767,51 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
        }
        new_primary = elect_new_primary(&elect_ipv4, &new_routelist,
                                        service_order, n_service_order);
-       (void)set_new_primary(&S_primary_ipv4, new_primary, "IPv4");
-       update_ipv4(S_primary_ipv4, new_routelist, &keys);
+       update_nwi_state_ipv4(S_nwi_state, new_routelist);
+
+       if (global_ipv4_changed) {
+           (void)set_new_primary(&S_primary_ipv4, new_primary, "IPv4");
+           update_ipv4(S_primary_ipv4, new_routelist, &keys);
+       }
+       else if (new_routelist != NULL) {
+           free(new_routelist);
+           new_routelist = NULL;
+       }
        my_CFRelease(&new_primary);
     }
-    if (global_ipv6_changed) {
-       CFStringRef new_primary;
+    if (global_ipv6_changed || dnsinfo_changed) {
+       IPv6RankedListRef       list = NULL;
+       CFStringRef             new_primary;
+       int                     size;
+
+       size = (n_services != 0)
+           ? (sizeof(IPv6RankedList)
+              + IPv6RankedListComputeSize(n_services)) : 0;
+
+       if (size != 0) {
+           list = malloc(size);
+       }
+       if (list != NULL) {
+           list->count = 0;
+           list->size = size;
+       }
 
        if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
            SCLog(TRUE, LOG_NOTICE,
                  CFSTR("IPMonitor: IPv6 service election"));
        }
-       new_primary = elect_new_primary(&elect_ipv6, NULL,
+       new_primary = elect_new_primary(&elect_ipv6, list,
                                        service_order, n_service_order);
-       (void)set_new_primary(&S_primary_ipv6, new_primary, "IPv6");
-       update_ipv6(services_info, S_primary_ipv6, &keys);
+       update_nwi_state_ipv6(S_nwi_state, list);
+
+       if (global_ipv6_changed) {
+           (void)set_new_primary(&S_primary_ipv6, new_primary, "IPv6");
+           update_ipv6(services_info, S_primary_ipv6, &keys);
+       }
+
+       if (list != NULL) {
+           free(list);
+       }
        my_CFRelease(&new_primary);
     }
     if (global_ipv4_changed || global_ipv6_changed) {
@@ -4001,6 +4871,7 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
 
        if (set_new_primary(&S_primary_dns, new_primary_dns, "DNS")) {
            update_dns(services_info, S_primary_dns, &keys);
+           dns_changed = TRUE;
            dnsinfo_changed = TRUE;
        }
        if (set_new_primary(&S_primary_proxies, new_primary_proxies, "Proxies")) {
@@ -4009,18 +4880,69 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
 #if    !TARGET_OS_IPHONE
        if (set_new_primary(&S_primary_smb, new_primary_smb, "SMB")) {
            update_smb(services_info, S_primary_smb, &keys);
+           smb_changed = TRUE;
        }
 #endif /* !TARGET_OS_IPHONE */
     }
+    if (dnsinfo_changed || global_ipv4_changed || global_ipv6_changed) {
+       if (S_nwi_state != NULL) {
+           S_nwi_state->generation_count = mach_absolute_time();
+           if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
+               syslog(LOG_NOTICE, "Updating network information");
+               _nwi_state_dump(LOG_NOTICE, S_nwi_state);
+           }
+           if (_nwi_state_store(S_nwi_state) == FALSE) {
+               SCLog(TRUE, LOG_ERR, CFSTR("Notifying nwi_state_store failed"));
+           }
+       }
+    }
     if (dnsinfo_changed) {
        update_dnsinfo(services_info, S_primary_dns, &keys, service_order);
     }
-    if (proxies_changed || dnsinfo_changed) {  // note: supplemental Proxies may follow supplemental DNS
+    if (proxies_changed ||
+       (dnsinfo_changed && (G_supplemental_proxies_follow_dns != NULL) && CFBooleanGetValue(G_supplemental_proxies_follow_dns))
+       ) {
+       // if proxy change OR supplemental Proxies follow supplemental DNS
        update_proxies(services_info, S_primary_proxies, &keys, service_order);
+       proxies_changed = TRUE;
     }
     my_CFRelease(&service_changes);
     my_CFRelease(&services_info);
-    keyChangeListApplyToStore(&keys, session);
+    my_CFRelease(&if_rank_changes);
+    changes_state = nwi_state_diff(old_nwi_state, S_nwi_state);
+    if ((S_IPMonitor_debug & kDebugFlag2) != 0) {
+       syslog(LOG_NOTICE, "network information diffs: ");
+       _nwi_state_dump(LOG_NOTICE, changes_state);
+    }
+    network_change_msg =
+       generate_log_changes(changes_state,
+                            dns_changed,
+                            dnsinfo_changed,
+                            old_primary_dns,
+                            proxies_changed,
+                            old_primary_proxy,
+#if    !TARGET_OS_IPHONE
+                            smb_changed,
+                            old_primary_smb
+#else  // !TARGET_OS_IPHONE
+                            FALSE,
+                            NULL
+#endif // !TARGET_OS_IPHONE
+                            );
+    keyChangeListApplyToStore(&keys, session, network_change_msg);
+    my_CFRelease(&old_primary_dns);
+    my_CFRelease(&old_primary_proxy);
+#if    !TARGET_OS_IPHONE
+    my_CFRelease(&old_primary_smb);
+#endif // !TARGET_OS_IPHONE
+    my_CFRelease(&network_change_msg);
+
+    if (changes_state != NULL) {
+       nwi_state_release(changes_state);
+    }
+    if (old_nwi_state != NULL) {
+       nwi_state_release(old_nwi_state);
+    }
     keyChangeListFree(&keys);
     return;
 }
@@ -4029,6 +4951,7 @@ static void
 ip_plugin_init()
 {
     CFMutableArrayRef  keys = NULL;
+    CFStringRef                pattern;
     CFMutableArrayRef  patterns = NULL;
     CFRunLoopSourceRef rls = NULL;
 
@@ -4081,15 +5004,15 @@ ip_plugin_init()
                                                     kSCDynamicStoreDomainSetup,
                                                     kSCEntNetIPv4);
     S_state_service_prefix
-       = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@/"),
-                                 kSCDynamicStoreDomainState,
-                                 kSCCompNetwork,
-                                 kSCCompService);
+       = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                     kSCDynamicStoreDomainState,
+                                                     CFSTR(""),
+                                                     NULL);
     S_setup_service_prefix
-       = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@/"),
-                                 kSCDynamicStoreDomainSetup,
-                                 kSCCompNetwork,
-                                 kSCCompService);
+       = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                     kSCDynamicStoreDomainSetup,
+                                                     CFSTR(""),
+                                                     NULL);
     S_service_state_dict
        = CFDictionaryCreateMutable(NULL, 0,
                                    &kCFTypeDictionaryKeyCallBacks,
@@ -4111,6 +5034,14 @@ ip_plugin_init()
     /* register for State: and Setup: per-service notifications */
     add_service_keys(kSCCompAnyRegex, keys, patterns);
 
+    /* register for State: per-service PPP/VPN/IPSec status notifications */
+    add_status_keys(patterns);
+
+    /* register for interface rank notifications */
+    pattern = if_rank_key_copy(kSCCompAnyRegex);
+    CFArrayAppendValue(patterns, pattern);
+    CFRelease(pattern);
+
     /* add notifier for ServiceOrder/PPPOverridePrimary changes for IPv4 */
     CFArrayAppendValue(keys, S_setup_global_ipv4);
 
@@ -4149,7 +5080,7 @@ ip_plugin_init()
     CFRelease(rls);
 
     /* initialize dns configuration */
-    dns_configuration_set(NULL, NULL, NULL, NULL, NULL);
+    (void)dns_configuration_set(NULL, NULL, NULL, NULL, NULL);
 #if    !TARGET_OS_IPHONE
     empty_dns();
 #endif /* !TARGET_OS_IPHONE */
@@ -4160,6 +5091,8 @@ ip_plugin_init()
     (void)SCDynamicStoreRemoveValue(S_session, S_state_global_smb);
 #endif /* !TARGET_OS_IPHONE */
 
+    if_rank_dict_init();
+
   done:
     my_CFRelease(&keys);
     my_CFRelease(&patterns);
@@ -4179,7 +5112,7 @@ static boolean_t
 S_get_plist_boolean(CFDictionaryRef plist, CFStringRef key,
                    boolean_t def)
 {
-    CFBooleanRef       b;
+    CFBooleanRef       b;
     boolean_t          ret = def;
 
     b = isA_CFBoolean(CFDictionaryGetValue(plist, key));
@@ -4193,7 +5126,7 @@ __private_extern__
 void
 load_IPMonitor(CFBundleRef bundle, Boolean bundleVerbose)
 {
-    CFDictionaryRef    info_dict;
+    CFDictionaryRef    info_dict;
 
     info_dict = CFBundleGetInfoDictionary(bundle);
     if (info_dict != NULL) {
@@ -4225,6 +5158,10 @@ load_IPMonitor(CFBundleRef bundle, Boolean bundleVerbose)
 }
 
 
+#pragma mark -
+#pragma mark Standalone test code
+
+
 #ifdef TEST_IPMONITOR
 #include "dns-configuration.c"
 #include "set-hostname.c"
@@ -4263,58 +5200,58 @@ struct ipv4_service_contents {
 };
 
 /*
- *  addr       mask            dest            router          ifname  pri  primaryRank
+ *  addr       mask            dest            router          ifname  pri  primaryRank
  */
 struct ipv4_service_contents en0_10 = {
-    "10.0.0.10", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  10,  NULL
+    "10.0.0.10", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  10,  NULL
 };
 
 struct ipv4_service_contents en0_15 = {
-    "10.0.0.19", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  15,  NULL
+    "10.0.0.19", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  15,  NULL
 };
 
 struct ipv4_service_contents en0_30 = {
-    "10.0.0.11", "255.255.255.0", NULL,        "10.0.0.1",     "en0",  30,  NULL
+    "10.0.0.11", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  30,  NULL
 };
 
 struct ipv4_service_contents en0_40 = {
-    "10.0.0.12", "255.255.255.0", NULL,        "10.0.0.1",     "en0",  40,  NULL
+    "10.0.0.12", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  40,  NULL
 };
 
 struct ipv4_service_contents en0_50 = {
-    "10.0.0.13", "255.255.255.0", NULL,        "10.0.0.1",     "en0",  50,  NULL
+    "10.0.0.13", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  50,  NULL
 };
 
 struct ipv4_service_contents en0_110 = {
-    "192.168.2.10", "255.255.255.0", NULL,     "192.168.2.1",  "en0",  110, NULL
+    "192.168.2.10", "255.255.255.0", NULL,     "192.168.2.1",  "en0",  110, NULL
 };
 
 struct ipv4_service_contents en0_1 = {
-    "17.202.40.191", "255.255.252.0", NULL,    "17.202.20.1",  "en0",  1,   NULL
+    "17.202.40.191", "255.255.252.0", NULL,    "17.202.20.1",  "en0",  1,   NULL
 };
 
 struct ipv4_service_contents en1_20 = {
-    "10.0.0.20", "255.255.255.0", NULL,        "10.0.0.1",     "en1",  20,  NULL
+    "10.0.0.20", "255.255.255.0", NULL,                "10.0.0.1",     "en1",  20,  NULL
 };
 
 struct ipv4_service_contents en1_2 = {
-    "17.202.42.24", "255.255.252.0", NULL,     "17.202.20.1",  "en1",  2,   NULL
+    "17.202.42.24", "255.255.252.0", NULL,     "17.202.20.1",  "en1",  2,   NULL
 };
 
 struct ipv4_service_contents en1_125 = {
-    "192.168.2.20", "255.255.255.0", NULL,     "192.168.2.1",  "en1",  125, NULL
+    "192.168.2.20", "255.255.255.0", NULL,     "192.168.2.1",  "en1",  125, NULL
 };
 
 struct ipv4_service_contents fw0_25 = {
-    "192.168.2.30", "255.255.255.0", NULL,     "192.168.2.1",  "fw0",  25,  NULL
+    "192.168.2.30", "255.255.255.0", NULL,     "192.168.2.1",  "fw0",  25,  NULL
 };
 
 struct ipv4_service_contents fw0_21 = {
-    "192.168.3.30", "255.255.255.0", NULL,     "192.168.3.1",  "fw0",  21,  NULL
+    "192.168.3.30", "255.255.255.0", NULL,     "192.168.3.1",  "fw0",  21,  NULL
 };
 
 struct ipv4_service_contents ppp0_0_1 = {
-    "17.219.156.22", NULL, "17.219.156.1",     "17.219.156.1", "ppp0", 0,   NULL
+    "17.219.156.22", NULL, "17.219.156.1",     "17.219.156.1", "ppp0", 0,   NULL
 };
 
 struct ipv4_service_contents en0_test6 = {
@@ -4337,23 +5274,23 @@ struct ipv4_service_contents en2_test7 = {
     "17.255.98.164",  "255.255.240.0", NULL,   "17.255.96.1",  "en2",  1,   NULL
 };
 struct ipv4_service_contents fw0_test6_and_7 = {
-    "169.254.11.33",  "255.255.0.0", NULL,     NULL,           "fw0", UINT_MAX,  NULL
+    "169.254.11.33",  "255.255.0.0", NULL,     NULL,           "fw0", 0x0ffffff,  NULL
 };
 
 struct ipv4_service_contents en0_10_last = {
-    "10.0.0.10", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  10,  &kSCValNetServicePrimaryRankLast
+    "10.0.0.10", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  10,  &kSCValNetServicePrimaryRankLast
 };
 
 struct ipv4_service_contents en0_10_never = {
-    "10.0.0.10", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  10,  &kSCValNetServicePrimaryRankNever
+    "10.0.0.10", "255.255.255.0", NULL,                "10.0.0.1",     "en0",  10,  &kSCValNetServicePrimaryRankNever
 };
 
 struct ipv4_service_contents en1_20_first = {
-    "10.0.0.20", "255.255.255.0", NULL,        "10.0.0.1",     "en1",  20,  &kSCValNetServicePrimaryRankFirst
+    "10.0.0.20", "255.255.255.0", NULL,                "10.0.0.1",     "en1",  20,  &kSCValNetServicePrimaryRankFirst
 };
 
 struct ipv4_service_contents en1_20_never = {
-    "10.0.0.20", "255.255.255.0", NULL,        "10.0.0.1",     "en1",  20,  &kSCValNetServicePrimaryRankNever
+    "10.0.0.20", "255.255.255.0", NULL,                "10.0.0.1",     "en1",  20,  &kSCValNetServicePrimaryRankNever
 };
 
 struct ipv4_service_contents * test1[] = {
@@ -4551,6 +5488,19 @@ make_IPv4RouteList(struct ipv4_service_contents * * this_test)
            fprintf(stderr, "IPv4RouteListCreateWithDictionary failed\n");
            exit(1);
        }
+
+       (*scan_test)->rank = RankMake((*scan_test)->rank, kRankAssertionDefault);
+
+       if ((*scan_test)->primaryRank != NULL) {
+           (*scan_test)->rank = RankMake((*scan_test)->rank,
+                                            PrimaryRankGetRankAssertion(*(*scan_test)->primaryRank));
+       }
+
+       if ((*scan_test)->router == NULL) {
+           (*scan_test)->rank = RankMake((*scan_test)->rank,
+                                           PrimaryRankGetRankAssertion(kSCValNetServicePrimaryRankLast));
+       }
+
        ret = IPv4RouteListAddRouteList(ret, 1, r, (*scan_test)->rank);
        if (r != routes) {
            free(r);
@@ -4602,6 +5552,13 @@ run_test(const char * name, struct ipv4_service_contents * * this_test)
            CFRelease(descr);
        }
 
+       (*scan_test)->rank = RankMake((*scan_test)->rank, kRankAssertionDefault);
+
+       if ((*scan_test)->primaryRank != NULL) {
+           (*scan_test)->rank = RankMake((*scan_test)->rank,
+                                           PrimaryRankGetRankAssertion(*(*scan_test)->primaryRank));
+       }
+
        routes1 = IPv4RouteListAddRouteList(routes1, 1, r, (*scan_test)->rank);
        if (r != routes) {
            free(r);
@@ -4637,6 +5594,11 @@ run_test(const char * name, struct ipv4_service_contents * * this_test)
            SCLog(TRUE, LOG_NOTICE, CFSTR("test: Adding %@"), descr);
            CFRelease(descr);
        }
+       if ((*scan_test)->primaryRank != NULL) {
+           (*scan_test)->rank = RankMake((*scan_test)->rank,
+                                           PrimaryRankGetRankAssertion(*(*scan_test)->primaryRank));
+       }
+
        routes2 = IPv4RouteListAddRouteList(routes2, 1, r, (*scan_test)->rank);
        if (r != routes) {
            free(r);
@@ -4694,12 +5656,10 @@ compare_callback(IPv4RouteListApplyCommand cmd, IPv4RouteRef route, void * arg)
     case kIPv4RouteListAddRouteCommand:
        printf("Add new[%ld] = ", route - context->new->list);
        IPv4RoutePrint(route);
-       printf("\n");
        break;
     case kIPv4RouteListRemoveRouteCommand:
        printf("Remove old[%ld] = ", route - context->old->list);
        IPv4RoutePrint(route);
-       printf("\n");
        break;
     default:
        break;
@@ -4713,7 +5673,7 @@ compare_tests(struct ipv4_service_contents * * old_test,
 {
     IPv4RouteListRef   new_routes;
     IPv4RouteListRef   old_routes;
-    compare_context_t  context;
+    compare_context_t  context;
 
     old_routes = make_IPv4RouteList(old_test);
     new_routes = make_IPv4RouteList(new_test);
index 827b99fa02663aecc901f08fc09951657c27b1ed..76d60fac9f07fc09d1321439df1cfb98c64a5953 100644 (file)
@@ -46,7 +46,7 @@
 #define ORDER_KEY              CFSTR("__ORDER__")
 
 
-static CFBooleanRef    S_proxies_follow_dns    = NULL;
+CFBooleanRef   G_supplemental_proxies_follow_dns       = NULL;
 
 
 static void
@@ -67,7 +67,7 @@ add_proxy(CFMutableArrayRef proxies, CFMutableDictionaryRef proxy)
                }
        }
 
-       order = CFNumberCreate(NULL, kCFNumberIntType, &n_proxies);
+       order = CFNumberCreate(NULL, kCFNumberCFIndexType, &n_proxies);
        CFDictionarySetValue(proxy, ORDER_KEY, order);
        CFRelease(order);
 
@@ -191,7 +191,7 @@ add_supplemental_proxies(CFMutableArrayRef proxies, CFDictionaryRef services, CF
                        continue;
                }
 
-               if ((S_proxies_follow_dns != NULL) && CFBooleanGetValue(S_proxies_follow_dns)) {
+               if ((G_supplemental_proxies_follow_dns != NULL) && CFBooleanGetValue(G_supplemental_proxies_follow_dns)) {
                        CFDictionaryRef dns;
                        CFArrayRef      matchDomains;
                        CFArrayRef      matchOrders;
@@ -545,7 +545,7 @@ compareDomain(const void *val1, const void *val2, void *context)
 
 
 __private_extern__
-CFDictionaryRef
+CF_RETURNS_RETAINED CFDictionaryRef
 proxy_configuration_update(CFDictionaryRef     defaultProxy,
                           CFDictionaryRef      services,
                           CFArrayRef           serviceOrder)
@@ -558,10 +558,6 @@ proxy_configuration_update(CFDictionaryRef defaultProxy,
        CFDictionaryRef         proxy;
        CFMutableArrayRef       proxies;
 
-       SCLog(TRUE, LOG_DEBUG, CFSTR("defaultProxy : %@"), defaultProxy ? defaultProxy : (CFTypeRef)CFSTR("NULL"));
-       SCLog(TRUE, LOG_DEBUG, CFSTR("services : %@"), services ? services : (CFTypeRef)CFSTR("NULL"));
-       SCLog(TRUE, LOG_DEBUG, CFSTR("serviceOrder : %@"), serviceOrder ? serviceOrder : (CFTypeRef)CFSTR("NULL"));
-
        // establish full list of proxies
 
        proxies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
@@ -672,14 +668,18 @@ proxy_configuration_init(CFBundleRef bundle)
 
        dict = CFBundleGetInfoDictionary(bundle);
        if (isA_CFDictionary(dict)) {
-               S_proxies_follow_dns = CFDictionaryGetValue(dict, CFSTR("SupplementalProxiesFollowSupplementalDNS"));
-               S_proxies_follow_dns = isA_CFBoolean(S_proxies_follow_dns);
+               G_supplemental_proxies_follow_dns = CFDictionaryGetValue(dict, CFSTR("SupplementalProxiesFollowSupplementalDNS"));
+               G_supplemental_proxies_follow_dns = isA_CFBoolean(G_supplemental_proxies_follow_dns);
        }
 
        return;
 }
 
 
+#pragma mark -
+#pragma mark Standalone test code
+
+
 #ifdef MAIN
 
 static void
index c03d9e4ff2f9864dbc92e02eb335b64b9a7095c0..fbb233c0c8d27065e1e467baae518d31e01cace4 100644 (file)
 #include <sys/cdefs.h>
 #include <CoreFoundation/CoreFoundation.h>
 
+
+CFBooleanRef   G_supplemental_proxies_follow_dns;
+
+
 __BEGIN_DECLS
 
-void           proxy_configuration_init        (CFBundleRef            bundle);
+__private_extern__
+void
+proxy_configuration_init       (CFBundleRef            bundle);
 
 
-CFDictionaryRef        proxy_configuration_update      (CFDictionaryRef        defaultProxy,
-                                                CFDictionaryRef        services,
-                                                CFArrayRef             serviceOrder);
+__private_extern__
+CF_RETURNS_RETAINED CFDictionaryRef
+proxy_configuration_update     (CFDictionaryRef        defaultProxy,
+                                CFDictionaryRef        services,
+                                CFArrayRef             serviceOrder);
 
 __END_DECLS
 
index 8d8087065d36ba7aa216393bf473876b73b87957..6ebcafd1c6ec1ece56f79fdaa2fc232197e0010f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -53,6 +53,7 @@ static Boolean                        _verbose        = FALSE;
 
 #define        HOSTNAME_NOTIFY_KEY     "com.apple.system.hostname"
 
+CFStringRef copy_dhcp_hostname(CFStringRef serviceID);
 
 static void
 set_hostname(CFStringRef hostname)
@@ -308,31 +309,6 @@ copy_primary_ip(SCDynamicStoreRef store, CFStringRef serviceID)
        return address;
 }
 
-
-#define        DHCP_OPTION_HOSTNAME    12
-
-static CFStringRef
-copy_dhcp_name(SCDynamicStoreRef store, CFStringRef serviceID)
-{
-       CFDictionaryRef info;
-       CFStringRef     name    = NULL;
-
-       info = SCDynamicStoreCopyDHCPInfo(store, serviceID);
-       if (info != NULL) {
-               CFDataRef       data;
-
-               data = DHCPInfoGetOptionData(info, DHCP_OPTION_HOSTNAME);
-               if (data != NULL) {
-                       name = CFStringCreateFromExternalRepresentation(NULL, data, kCFStringEncodingUTF8);
-               }
-
-               CFRelease(info);
-       }
-
-       return name;
-}
-
-
 static void
 reverseDNSComplete(int32_t status, char *host, char *serv, void *context)
 {
@@ -472,50 +448,28 @@ getnameinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, voi
 static void
 start_dns_query(SCDynamicStoreRef store, CFStringRef address)
 {
-       char                            addr[64];
+       union {
+               struct sockaddr         sa;
+               struct sockaddr_in      sin;
+               struct sockaddr_in6     sin6;
+       } addr;
+       char                            buf[64];
        SCNetworkReachabilityFlags      flags;
        Boolean                         haveDNS;
        Boolean                         ok;
-       struct sockaddr                 *sa;
-       struct sockaddr_in              sin;
-       struct sockaddr_in6             sin6;
 
-       if (_SC_cfstring_to_cstring(address, addr, sizeof(addr), kCFStringEncodingASCII) == NULL) {
+       if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
                SCLog(TRUE, LOG_ERR, CFSTR("could not convert [primary] address"));
                return;
        }
 
-       bzero(&sin, sizeof(sin));
-       sin.sin_len    = sizeof(sin);
-       sin.sin_family = AF_INET;
-
-       bzero(&sin6, sizeof(sin6));
-       sin6.sin6_len    = sizeof(sin6);
-       sin6.sin6_family = AF_INET6;
-
-       if (inet_aton(addr, &sin.sin_addr) == 1) {
-               /*
-                * if IPv4 address
-                */
-               sa = (struct sockaddr *)&sin;
-       } else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr) == 1) {
-               /*
-                * if IPv6 address
-                */
-               char    *p;
-
-               p = strchr(addr, '%');
-               if (p != NULL) {
-                       sin6.sin6_scope_id = if_nametoindex(p + 1);
-               }
-
-               sa = (struct sockaddr *)&sin6;
-       } else {
-               goto done;
+       if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
+               /* if not an IP[v6] address */
+               SCLog(TRUE, LOG_ERR, CFSTR("could not parse [primary] address"));
+               return;
        }
 
-
-       ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, sa);
+       ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, &addr.sa);
        if (ok) {
                if (!(flags & kSCNetworkReachabilityFlagsReachable) ||
                    (flags & kSCNetworkReachabilityFlagsConnectionRequired)) {
@@ -538,8 +492,8 @@ start_dns_query(SCDynamicStoreRef store, CFStringRef address)
                (void) gettimeofday(&dnsQueryStart, NULL);
 
                error = getnameinfo_async_start(&mp,
-                                               sa,
-                                               sa->sa_len,
+                                               &addr.sa,
+                                               addr.sa.sa_len,
                                                NI_NAMEREQD,    // flags
                                                reverseDNSComplete,
                                                NULL);
@@ -612,7 +566,7 @@ update_hostname(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
 
        // get DHCP provided name, if available
 
-       hostname = copy_dhcp_name(store, serviceID);
+       hostname = copy_dhcp_hostname(serviceID);
        if (hostname != NULL) {
                SCLog(TRUE, LOG_INFO, CFSTR("hostname (DHCP) = %@"), hostname);
                set_hostname(hostname);
index 109779d29ffa7bf58fd80a66ec8b170219b5e43e..3315cce2ef281477bda21455cf773a568c384f82 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -29,6 +29,7 @@
 
 __BEGIN_DECLS
 
+__private_extern__
 void   load_hostname           (Boolean        verbose);
 
 __END_DECLS
index 3325efcd2888cbb86a3c40955b58048286566381..8c06cd69d528668989842983319dc047350155f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -645,49 +645,28 @@ getnameinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, voi
 static Boolean
 start_dns_query(SCDynamicStoreRef store, CFStringRef address)
 {
-       char                            addr[64];
+       union {
+               struct sockaddr         sa;
+               struct sockaddr_in      sin;
+               struct sockaddr_in6     sin6;
+       } addr;
+       char                            buf[64];
        SCNetworkReachabilityFlags      flags;
        Boolean                         haveDNS;
        Boolean                         ok      = FALSE;
-       struct sockaddr                 *sa;
-       struct sockaddr_in              sin;
-       struct sockaddr_in6             sin6;
 
-       if (_SC_cfstring_to_cstring(address, addr, sizeof(addr), kCFStringEncodingASCII) == NULL) {
+       if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
                SCLog(TRUE, LOG_ERR, CFSTR("could not convert [primary] address"));
                return FALSE;
        }
 
-       bzero(&sin, sizeof(sin));
-       sin.sin_len    = sizeof(sin);
-       sin.sin_family = AF_INET;
-
-       bzero(&sin6, sizeof(sin6));
-       sin6.sin6_len    = sizeof(sin6);
-       sin6.sin6_family = AF_INET6;
-
-       if (inet_aton(addr, &sin.sin_addr) == 1) {
-               /*
-                * if IPv4 address
-                */
-               sa = (struct sockaddr *)&sin;
-       } else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr) == 1) {
-               /*
-                * if IPv6 address
-                */
-               char    *p;
-
-               p = strchr(addr, '%');
-               if (p != NULL) {
-                       sin6.sin6_scope_id = if_nametoindex(p + 1);
-               }
-
-               sa = (struct sockaddr *)&sin6;
-       } else {
-               goto done;
+       if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
+               /* if not an IP[v6] address */
+               SCLog(TRUE, LOG_ERR, CFSTR("could not parse [primary] address"));
+               return FALSE;
        }
 
-       ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, sa);
+       ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, &addr.sa);
        if (ok) {
                if (!(flags & kSCNetworkReachabilityFlagsReachable) ||
                    (flags & kSCNetworkReachabilityFlagsConnectionRequired)) {
@@ -710,8 +689,8 @@ start_dns_query(SCDynamicStoreRef store, CFStringRef address)
                (void) gettimeofday(&dnsQueryStart, NULL);
 
                error = getnameinfo_async_start(&mp,
-                                               sa,
-                                               sa->sa_len,
+                                               &addr.sa,
+                                               addr.sa.sa_len,
                                                NI_NAMEREQD,    // flags
                                                reverseDNSComplete,
                                                (void *)store);
index 46ece86ad97f2801800d6b5a52ef37a8ed3bc312..d1fdf3ae95af5c96aa020768a6ba11029e09914e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -28,6 +28,7 @@
 
 __BEGIN_DECLS
 
+__private_extern__
 void   load_smb_configuration          (Boolean        verbose);
 
 __END_DECLS
index 6698c5b6016156c545ca9903280aaa128c83949c..410103d5248adb5b08261dac42cf070e8ba4d98a 100644 (file)
@@ -758,8 +758,8 @@ Old Routes = <IPv4RouteList[4]> = {
  3. Dest 10.0.0.0 Mask 255.255.255.0 Gate 10.0.0.20 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED]
 }
 New Routes = <IPv4RouteList[2]> = {
- 0. Dest 0.0.0.0 Mask 0.0.0.0 Gate 10.0.0.1 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED*]
- 1. Dest 10.0.0.0 Mask 255.255.255.0 Gate 10.0.0.20 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED*]
+ 0. Dest 0.0.0.0 Mask 0.0.0.0 Gate 10.0.0.1 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED]
+ 1. Dest 10.0.0.0 Mask 255.255.255.0 Gate 10.0.0.20 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED]
 }
 Remove old[0] = Dest 0.0.0.0 Mask 0.0.0.0 Gate 10.0.0.1 Ifp en0 Ifa 10.0.0.10
 Remove old[2] = Dest 10.0.0.0 Mask 255.255.255.0 Gate 10.0.0.10 Ifp en0 Ifa 10.0.0.10
index d2650f6b8c1d28ac6f2bdda4da9ef5f1f3e333cb..5efd37216fabc42c2e8b7b18dda6dc42572d0e5c 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
 </dict>
 </plist>
index ae4d87ab1c6f1445f1a83bc249481d15fcb5c4f1..639f9aea694f6810020688567b5115e3aa9dec23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2001-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <net/ethernet.h>
 #include <net/if.h>
 #include <net/if_types.h>
+#include <pthread.h>
+#include <vproc.h>
+
+#include <CommonCrypto/CommonDigest.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 
@@ -149,12 +153,6 @@ static CFMutableArrayRef   S_iflist                = NULL;
  */
 static io_iterator_t           S_iter                  = MACH_PORT_NULL;
 
-/*
- * S_model
- *   Hardware model for this network configuration.
- */
-static CFStringRef             S_model                 = NULL;
-
 /*
  * S_notify
  *   notification object for receiving IOKit notifications of
@@ -207,6 +205,14 @@ static CFRunLoopTimerRef   S_timer                 = NULL;
 static double                  S_stack_timeout         = WAIT_STACK_TIMEOUT_DEFAULT;
 static double                  S_quiet_timeout         = WAIT_QUIET_TIMEOUT_DEFAULT;
 
+#if    !TARGET_OS_EMBEDDED
+/*
+ * S_vproc_transaction
+ *   The vproc transaction used to keep launchd from sending us
+ *   a SIGKILL before we've had a chance to set the platform UUID
+ */
+vproc_transaction_t            S_vproc_transaction     = NULL;
+#endif // !TARGET_OS_EMBEDDED
 
 /*
  * Virtual network interface configuration
@@ -234,34 +240,8 @@ addTimestamp(CFMutableDictionaryRef dict, CFStringRef key)
 }
 
 #define        INTERFACES                      CFSTR("Interfaces")
-#define        MODEL                           CFSTR("Model")
 #define        NETWORK_INTERFACES_PREFS        CFSTR("NetworkInterfaces.plist")
 
-static CFStringRef
-hw_model()
-{
-    if (S_model == NULL) {
-       char    hwModel[64];
-       int     mib[]           = { CTL_HW, HW_MODEL };
-       size_t  n               = sizeof(hwModel);
-       int     ret;
-
-       // get HW model name
-       bzero(&hwModel, sizeof(hwModel));
-       ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &hwModel, &n, NULL, 0);
-       if (ret != 0) {
-           SCLog(TRUE, LOG_ERR, CFSTR("sysctl() CTL_HW/HW_MODEL failed: %s"), strerror(errno));
-           return NULL;
-       }
-       hwModel[sizeof(hwModel) - 1] = '\0';
-
-       S_model = CFStringCreateWithCString(NULL, hwModel, kCFStringEncodingASCII);
-    }
-
-    return S_model;
-
-}
-
 static CFComparisonResult
 if_unit_compare(const void *val1, const void *val2, void *context)
 {
@@ -327,7 +307,7 @@ writeInterfaceList(CFArrayRef if_list)
     }
 
     old_model = SCPreferencesGetValue(prefs, MODEL);
-    new_model = hw_model();
+    new_model = _SC_hw_model();
     if ((new_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
        // if new hardware
        if ((old_model != NULL) && (cur_list != NULL)) {
@@ -385,7 +365,7 @@ done:
     return;
 }
 
-static CFMutableArrayRef
+static CF_RETURNS_RETAINED CFMutableArrayRef
 readInterfaceList()
 {
     CFArrayRef         if_list;
@@ -408,7 +388,7 @@ readInterfaceList()
     if (old_model != NULL) {
        CFStringRef new_model;
 
-       new_model = hw_model();
+       new_model = _SC_hw_model();
        if (!_SC_CFEqual(old_model, new_model)) {
            // if interface list was created on other hardware
            if_list = NULL;
@@ -439,7 +419,7 @@ readInterfaceList()
     return (plist);
 }
 
-static CFMutableArrayRef
+static CF_RETURNS_RETAINED CFMutableArrayRef
 previouslyActiveInterfaces()
 {
     CFMutableArrayRef  active;
@@ -475,22 +455,16 @@ static void
 updateStore(void)
 {
     CFStringRef                key;
-    SCDynamicStoreRef  store;
-
-    store = SCDynamicStoreCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL, NULL);
-    if (store == NULL) {
-       return;
-    }
 
     key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" MY_PLUGIN_NAME),
                                  kSCDynamicStoreDomainPlugin);
-    (void)SCDynamicStoreSetValue(store, key, S_state);
+    (void)SCDynamicStoreSetValue(NULL, key, S_state);
     CFRelease(key);
-    CFRelease(store);
 
     return;
 }
 
+#if    !TARGET_OS_IPHONE
 static void
 updateBondInterfaceConfiguration(SCPreferencesRef prefs)
 {
@@ -519,6 +493,7 @@ updateBondInterfaceConfiguration(SCPreferencesRef prefs)
 
     return;
 }
+#endif // !TARGET_OS_IPHONE
 
 static void
 updateBridgeInterfaceConfiguration(SCPreferencesRef prefs)
@@ -604,7 +579,9 @@ updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef         prefs,
        }
     }
 
+#if    !TARGET_OS_IPHONE
     updateBondInterfaceConfiguration  (prefs);
+#endif // !TARGET_OS_IPHONE
     updateBridgeInterfaceConfiguration(prefs);
     updateVLANInterfaceConfiguration  (prefs);
 
@@ -752,7 +729,7 @@ typedef struct {
     CFMutableArrayRef      matches;
 } matchContext, *matchContextRef;
 
-static CFDictionaryRef
+static CF_RETURNS_RETAINED CFDictionaryRef
 thinInterfaceInfo(CFDictionaryRef info)
 {
     CFNumberRef        num;
@@ -1108,6 +1085,23 @@ getHighestUnitForType(CFNumberRef if_type)
     return (ret_unit);
 }
 
+/*
+ * Function: ensureInterfaceHasUnit
+ * Purpose:
+ *   Ensure that the SCNetworkInterfaceRef has a unit number.  If it doesn't,
+ *   release the interface and return NULL.
+ */
+static SCNetworkInterfaceRef
+ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if)
+{
+    if (net_if != NULL
+       && _SCNetworkInterfaceGetIOInterfaceUnit(net_if) == NULL) {
+       CFRelease(net_if);
+       net_if = NULL;
+    }
+    return (net_if);
+}
+
 #ifdef USE_REGISTRY_ENTRY_ID
 static kern_return_t
 registerInterfaceWithIORegistryEntryID(io_connect_t connect,
@@ -1136,7 +1130,7 @@ registerInterfaceWithIORegistryEntryID(io_connect_t connect,
 }
 
 static SCNetworkInterfaceRef
-lookupIORegistryEntryID(uint64_t entryID)
+copyInterfaceForIORegistryEntryID(uint64_t entryID)
 {
     io_registry_entry_t                entry           = MACH_PORT_NULL;
     SCNetworkInterfaceRef      interface       = NULL;
@@ -1187,6 +1181,16 @@ lookupIORegistryEntryID(uint64_t entryID)
     return (interface);
 
 }
+
+static SCNetworkInterfaceRef
+copyNamedInterfaceForIORegistryEntryID(uint64_t entryID)
+{
+    SCNetworkInterfaceRef      net_if;
+
+    net_if = copyInterfaceForIORegistryEntryID(entryID);
+    return (ensureInterfaceHasUnit(net_if));
+}
+
 #else  // USE_REGISTRY_ENTRY_ID
 /*
  * Function: registerInterface
@@ -1218,7 +1222,7 @@ registerInterfaceWithIOServicePath(io_connect_t   connect,
 }
 
 static SCNetworkInterfaceRef
-lookupIOKitPath(CFStringRef if_path)
+copyInterfaceForIOKitPath(CFStringRef if_path)
 {
     io_registry_entry_t                entry           = MACH_PORT_NULL;
     SCNetworkInterfaceRef      interface       = NULL;
@@ -1254,6 +1258,16 @@ lookupIOKitPath(CFStringRef if_path)
     return (interface);
 
 }
+
+static SCNetworkInterfaceRef
+copyNamedInterfaceForIOKitPath(CFStringRef if_path)
+{
+    SCNetworkInterfaceRef      net_if;
+
+    net_if = copyInterfaceForIOKitPath(if_path);
+    return (ensureInterfaceHasUnit(net_if));
+}
+
 #endif // USE_REGISTRY_ENTRY_ID
 
 static void
@@ -1318,7 +1332,7 @@ nameInterfaces(CFMutableArrayRef if_list)
     for (i = 0; i < n; i++) {
        uint64_t                entryID;
        SCNetworkInterfaceRef   interface;
-       Boolean                 ok      = TRUE;
+       SCNetworkInterfaceRef   new_interface;
        CFStringRef             path;
        CFStringRef             str;
        CFNumberRef             type;
@@ -1348,6 +1362,8 @@ nameInterfaces(CFMutableArrayRef if_list)
                && lookupInterfaceByAddress(S_prev_active_list, interface, &where) != NULL) {
                CFArrayRemoveValueAtIndex(S_prev_active_list, where);
            }
+
+           replaceInterface(interface);
        } else {
            CFDictionaryRef     dbdict;
            boolean_t           is_builtin;
@@ -1434,14 +1450,16 @@ nameInterfaces(CFMutableArrayRef if_list)
                                                        unit,
                                                        (dbdict == NULL) ? kIONetworkStackRegisterInterfaceWithLowestUnit
                                                                         : kIONetworkStackRegisterInterfaceWithUnit);
+           new_interface = copyNamedInterfaceForIORegistryEntryID(entryID);
 #else  // USE_REGISTRY_ENTRY_ID
            kr = registerInterfaceWithIOServicePath(S_connect,
                                                    path,
                                                    unit,
                                                    (dbdict == NULL) ? kRegisterInterface
                                                                     : kRegisterInterfaceWithFixedUnit);
+           new_interface = copyNamedInterfaceForIOKitPath(path);
 #endif // USE_REGISTRY_ENTRY_ID
-           if (kr != KERN_SUCCESS) {
+           if (new_interface == NULL) {
                const char  *signature;
 
                signature = (dbdict == NULL) ? "failed to name new interface"
@@ -1475,10 +1493,9 @@ nameInterfaces(CFMutableArrayRef if_list)
                    usleep(50 * 1000);  // sleep 50ms between attempts
                    goto retry;
                }
-
-               ok = FALSE;     // ... and don't update the database
-           } else {
-               SCNetworkInterfaceRef   new_interface;
+           }
+           else {
+               CFNumberRef     new_unit;
 
                if (retries > 0) {
                    SCLog(TRUE, LOG_ERR,
@@ -1511,51 +1528,37 @@ nameInterfaces(CFMutableArrayRef if_list)
 #endif // SHOW_NAMING_FAILURE
                }
 
-#ifdef USE_REGISTRY_ENTRY_ID
-               new_interface = lookupIORegistryEntryID(entryID);
-#else  // USE_REGISTRY_ENTRY_ID
-               new_interface = lookupIOKitPath(path);
-#endif // USE_REGISTRY_ENTRY_ID
-               if (new_interface != NULL) {
-                   CFNumberRef new_unit;
-
-                   new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface);
-                   if (CFEqual(unit, new_unit) == FALSE) {
-                       SCLog(S_debug, LOG_INFO,
-                             CFSTR(MY_PLUGIN_NAME
-                                   ": interface type %@ assigned "
-                                   "unit %@ instead of %@"),
-                             type, new_unit, unit);
-                   }
-                   if (S_debug) {
-                       displayInterface(new_interface);
-                   }
+               new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface);
+               if (CFEqual(unit, new_unit) == FALSE) {
+                   SCLog(S_debug, LOG_INFO,
+                         CFSTR(MY_PLUGIN_NAME
+                               ": interface type %@ assigned "
+                               "unit %@ instead of %@"),
+                         type, new_unit, unit);
+               }
+               if (S_debug) {
+                   displayInterface(new_interface);
+               }
 
-                   // update if_list (with the interface name & unit)
-                   CFArraySetValueAtIndex(if_list, i, new_interface);
-                   CFRelease(new_interface);
-                   interface = new_interface;  // if_list holds the reference
+               // update if_list (with the interface name & unit)
+               CFArraySetValueAtIndex(if_list, i, new_interface);
+               CFRelease(new_interface);
+               interface = new_interface;      // if_list holds the reference
 
-                   if (is_builtin && (S_prev_active_list != NULL)) {
-                       CFIndex where;
+               if (is_builtin && (S_prev_active_list != NULL)) {
+                   CFIndex     where;
 
-                       // update the list of [built-in] interfaces that were previously named
-                       if (lookupInterfaceByUnit(S_prev_active_list, interface, &where) != NULL) {
-                           SCLog(S_debug, LOG_INFO,
-                                 CFSTR(MY_PLUGIN_NAME ":   and updated database (new address)"));
-                           CFArrayRemoveValueAtIndex(S_prev_active_list, where);
-                       }
+                   // update the list of [built-in] interfaces that were previously named
+                   if (lookupInterfaceByUnit(S_prev_active_list, interface, &where) != NULL) {
+                       SCLog(S_debug, LOG_INFO,
+                             CFSTR(MY_PLUGIN_NAME ":   and updated database (new address)"));
+                       CFArrayRemoveValueAtIndex(S_prev_active_list, where);
                    }
                }
+               replaceInterface(interface);
            }
-
            CFRelease(unit);
        }
-
-       // update db
-       if (ok) {
-           replaceInterface(interface);
-       }
     }
     return;
 }
@@ -1647,6 +1650,7 @@ updateInterfaces()
     return;
 }
 
+#if    !TARGET_OS_EMBEDDED
 static CFComparisonResult
 compareMacAddress(const void *val1, const void *val2, void *context)
 {
@@ -1669,29 +1673,14 @@ compareMacAddress(const void *val1, const void *val2, void *context)
      return res;
 }
 
-#ifndef kIOPlatformUUIDKey
-#define kIOPlatformUUIDKey "IOPlatformUUID"
-#endif
-static void
-updatePlatformUUID()
+static CFStringRef
+copyEthernetUUID()
 {
     CFDataRef          addr;
     CFMutableArrayRef  addrs   = NULL;
-    CFStringRef                guid;
+    CFStringRef                guid    = NULL;
     CFIndex            i;
     CFIndex            n;
-    io_registry_entry_t        platform;
-
-    platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/");
-    if (platform == MACH_PORT_NULL) {
-       return;
-    }
-
-    guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0);
-    if (guid != NULL) {
-       // if GUID already defined
-       goto done;
-    }
 
     addrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0;
@@ -1738,8 +1727,7 @@ updatePlatformUUID()
     n = CFArrayGetCount(addrs);
     switch (n) {
        case 0 :
-           SCLog(TRUE, LOG_ERR,
-                 CFSTR(MY_PLUGIN_NAME ": no network interfaces, could not update platform UUID"));
+           // if no network interfaces
            break;
        default :
            // sort by MAC address
@@ -1749,7 +1737,6 @@ updatePlatformUUID()
        case 1 : {
            CFUUIDBytes         bytes   = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
                                            0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-           kern_return_t       kr;
            CFUUIDRef           uuid;
 
            // set GUID
@@ -1762,28 +1749,74 @@ updatePlatformUUID()
            CFRelease(uuid);
 
            SCLog(TRUE, LOG_INFO,
-                 CFSTR(MY_PLUGIN_NAME ": setting platform UUID = %@"),
+                 CFSTR(MY_PLUGIN_NAME ": setting platform UUID [MAC] = %@"),
                  guid);
-           kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid);
-           if (kr != KERN_SUCCESS) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
-                     kr);
-           }
-
-           addTimestamp(S_state, CFSTR("*PLATFORM-UUID*"));
-           updateStore();
            break;
        }
     }
 
+    if (addrs != NULL) CFRelease(addrs);
+    return guid;
+}
+
+#ifndef kIOPlatformUUIDKey
+#define kIOPlatformUUIDKey "IOPlatformUUID"
+#endif
+static void
+updatePlatformUUID()
+{
+    CFStringRef                guid    = NULL;
+    kern_return_t      kr;
+    io_registry_entry_t        platform;
+
+    platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/");
+    if (platform == MACH_PORT_NULL) {
+       goto done;
+    }
+
+    guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0);
+    if (guid != NULL) {
+       // if GUID already defined
+       goto done;
+    }
+
+    guid = copyEthernetUUID();
+    if (guid == NULL) {
+       CFUUIDRef   uuid;
+
+       uuid = CFUUIDCreate(NULL);
+       guid = CFUUIDCreateString(NULL, uuid);
+       CFRelease(uuid);
+
+       SCLog(TRUE, LOG_INFO,
+             CFSTR(MY_PLUGIN_NAME ": setting platform UUID [random] = %@"),
+             guid);
+    }
+
+if (getenv("DO_NOT_SET_PLATFORM_UUID") == NULL) {
+    kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid);
+    if (kr != KERN_SUCCESS) {
+       SCLog(TRUE, LOG_ERR,
+             CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"),
+             kr);
+    }
+}
+
+    addTimestamp(S_state, CFSTR("*PLATFORM-UUID*"));
+    updateStore();
+
   done :
 
-    if (addrs != NULL) CFRelease(addrs);
+    if (S_vproc_transaction != NULL) {
+       vproc_transaction_end(NULL, S_vproc_transaction);
+       S_vproc_transaction = NULL;
+    }
+
     if (platform != MACH_PORT_NULL) IOObjectRelease(platform);
     if (guid != NULL) CFRelease(guid);
     return;
 }
+#endif // !TARGET_OS_EMBEDDED
 
 static void
 interfaceArrivalCallback(void *refcon, io_iterator_t iter)
@@ -1900,7 +1933,9 @@ quietCallback(void                *refcon,
     // grab (and name) any additional interfaces.
     interfaceArrivalCallback((void *)S_notify, S_iter);
 
+#if    !TARGET_OS_EMBEDDED
     updatePlatformUUID();
+#endif // !TARGET_OS_EMBEDDED
 
     return;
 }
@@ -1984,6 +2019,7 @@ iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, CFMutableStringRef
                                 (state & kIOServiceRegisteredState) ? "" : "!registered, ",
                                 (state & kIOServiceMatchedState)    ? "" : "!matched, ",
                                 (state & kIOServiceInactiveState)   ? "inactive, " : "",
+                                busy_state,
                                 accumulated_busy_time / kMillisecondScale);
            CFRelease(path);
        }
@@ -2014,7 +2050,7 @@ iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, CFMutableStringRef
     return;
 }
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 captureBusy()
 {
     int                        count           = 0;
@@ -2275,9 +2311,7 @@ exec_InterfaceNamer(void *arg)
     CFBundleRef                bundle  = (CFBundleRef)arg;
     CFDictionaryRef    dict;
 
-#if    !TARGET_OS_EMBEDDED
     pthread_setname_np(MY_PLUGIN_NAME " thread");
-#endif // !TARGET_OS_EMBEDDED
 
     dict = CFBundleGetInfoDictionary(bundle);
     if (isA_CFDictionary(dict)) {
@@ -2316,6 +2350,12 @@ exec_InterfaceNamer(void *arg)
        goto error;
     }
 
+#if    !TARGET_OS_EMBEDDED
+    // keep launchd from SIGKILL'ing us until after the platform-uuid has
+    // been updated
+    S_vproc_transaction = vproc_transaction_begin(NULL);
+#endif // !TARGET_OS_EMBEDDED
+
     goto done;
 
   error :
@@ -2353,10 +2393,8 @@ exec_InterfaceNamer(void *arg)
     }
 
   done :
-#if    !TARGET_OS_EMBEDDED
     CFRelease(bundle);
     CFRunLoopRun();
-#endif // !TARGET_OS_EMBEDDED
 
     return NULL;
 }
@@ -2365,27 +2403,21 @@ __private_extern__
 void
 load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose)
 {
+    pthread_attr_t  tattr;
+    pthread_t      tid;
+
     if (bundleVerbose) {
        S_debug = TRUE;
     }
 
-#if    !TARGET_OS_EMBEDDED
-    {
-       pthread_attr_t  tattr;
-       pthread_t       tid;
+    CFRetain(bundle);  // released in exec_InterfaceNamer
 
-       CFRetain(bundle);       // released in exec_InterfaceNamer
-
-       pthread_attr_init(&tattr);
-       pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
-       pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-//     pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
-       pthread_create(&tid, &tattr, exec_InterfaceNamer, bundle);
-       pthread_attr_destroy(&tattr);
-    }
-#else  // !TARGET_OS_EMBEDDED
-    (void)exec_InterfaceNamer(bundle);
-#endif // !TARGET_OS_EMBEDDED
+    pthread_attr_init(&tattr);
+    pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
+    pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+//  pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
+    pthread_create(&tid, &tattr, exec_InterfaceNamer, bundle);
+    pthread_attr_destroy(&tattr);
 
     return;
 }
@@ -2396,11 +2428,18 @@ load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose)
 int
 main(int argc, char ** argv)
 {
+    CFBundleRef bundle;
+
     _sc_log     = FALSE;
     _sc_verbose = (argc > 1) ? TRUE : FALSE;
 
-    load_InterfaceNamer(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
-    CFRunLoopRun();
+    S_debug = _sc_verbose;
+
+    bundle = CFBundleGetMainBundle();
+    CFRetain(bundle);  // released in exec_InterfaceNamer
+
+    (void)exec_InterfaceNamer();
+
     /* not reached */
     exit(0);
     return 0;
@@ -2411,6 +2450,7 @@ main(int argc, char ** argv)
 int
 main(int argc, char ** argv)
 {
+    CFStringRef        guid;
     CFArrayRef interfaces;
 
     _sc_log     = FALSE;
@@ -2434,6 +2474,11 @@ main(int argc, char ** argv)
        }
        CFRelease(interfaces);
     }
+
+    guid = copyEthernetUUID();
+    SCPrint(TRUE, stdout, CFSTR("copyEthernetUUID()  = %@\n"), (guid != NULL) ? guid : CFSTR("NULL"));
+    if (guid != NULL) CFRelease(guid);
+
     updatePlatformUUID();
     CFRelease(S_dblist);
     exit(0);
index 2b2602587e91be239d20adef28819e4ddc290d63..5473f521c4fab51f3e16695796d00312a34b9ac2 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>Requires</key>
        <array>
                <string>com.apple.SystemConfiguration.InterfaceNamer</string>
index 82487f37a297e06d0c4554fb77646d90d7d60c50..0830019a5a1e1c3516d43adaf662f589e387223b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2006, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include "cache.h"
 #include "ev_dlil.h"
 
+#ifndef kSCEntNetIdleRoute
+#define kSCEntNetIdleRoute       CFSTR("IdleRoute")
+#endif  /* kSCEntNetIdleRoute */
+
 static CFStringRef
 create_interface_key(const char * if_name)
 {
@@ -103,6 +107,88 @@ interface_update_status(const char *if_name, CFBooleanRef active,
        return;
 }
 
+
+#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
+static CFStringRef
+create_linkquality_key(const char * if_name)
+{
+       CFStringRef             interface;
+       CFStringRef             key;
+
+       interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
+       key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+                                                           kSCDynamicStoreDomainState,
+                                                           interface,
+                                                           kSCEntNetLinkQuality);
+       CFRelease(interface);
+       return (key);
+}
+
+
+__private_extern__
+void
+interface_update_quality_metric(const char *if_name,
+                               int quality)
+{
+       CFStringRef             key             = NULL;
+       CFMutableDictionaryRef  newDict         = NULL;
+       CFNumberRef             linkquality     = NULL;
+
+       key = create_linkquality_key(if_name);
+       newDict = copy_entity(key);
+
+       if (quality != IFNET_LQM_THRESH_UNKNOWN) {
+               linkquality = CFNumberCreate(NULL, kCFNumberIntType, &quality);
+               CFDictionarySetValue(newDict, kSCPropNetLinkQuality, linkquality);
+               CFRelease(linkquality);
+       } else {
+               CFDictionaryRemoveValue(newDict, kSCPropNetLinkQuality);
+       }
+
+       /* update status */
+       if (CFDictionaryGetCount(newDict) > 0) {
+               cache_SCDynamicStoreSetValue(store, key, newDict);
+       } else {
+               cache_SCDynamicStoreRemoveValue(store, key);
+       }
+
+       CFRelease(key);
+       CFRelease(newDict);
+       return;
+}
+
+
+static
+void
+link_update_quality_metric(const char *if_name)
+{
+       struct ifreq    ifr;
+       int             quality = IFNET_LQM_THRESH_UNKNOWN;
+       int             sock;
+
+       sock = dgram_socket(AF_INET);
+       if (sock == -1) {
+               SCLog(TRUE, LOG_NOTICE, CFSTR("socket_get_link_quality: socket open failed,  %s"), strerror(errno));
+               goto done;
+       }
+
+       bzero((char *)&ifr, sizeof(ifr));
+       snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
+
+       if (ioctl(sock, SIOCGIFLINKQUALITYMETRIC, (caddr_t)&ifr) != -1) {
+               quality = ifr.ifr_link_quality_metric;
+       }
+
+done:
+       interface_update_quality_metric(if_name, quality);
+       if (sock != -1)
+               close(sock);
+       return;
+
+}
+#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
+
+
 __private_extern__
 void
 interface_detaching(const char *if_name)
@@ -128,6 +214,13 @@ interface_remove(const char *if_name)
        key = create_interface_key(if_name);
        cache_SCDynamicStoreRemoveValue(store, key);
        CFRelease(key);
+
+#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
+       key = create_linkquality_key(if_name);
+       cache_SCDynamicStoreRemoveValue(store, key);
+       CFRelease(key);
+#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
+
        return;
 }
 
@@ -223,6 +316,9 @@ link_add(const char *if_name)
        }
        cache_SCDynamicStoreSetValue(store, cacheKey, newDict);
        link_update_status(if_name, TRUE);
+#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
+       link_update_quality_metric(if_name);
+#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */
        CFRelease(cacheKey);
        CFRelease(interface);
        if (newDict)    CFRelease(newDict);
@@ -284,3 +380,61 @@ link_remove(const char *if_name)
 
        return;
 }
+
+
+#ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
+#define INVALID_SOCKET_REF     -1
+static
+int
+socket_reference_count(const char* if_name) {
+       struct ifreq    ifr;
+       int             ref = INVALID_SOCKET_REF;
+       int             s;
+
+       s = dgram_socket(AF_INET);
+       if (s == -1) {
+               return (ref);
+       }
+
+       bzero((char *)&ifr, sizeof(ifr));
+       snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
+
+       if (ioctl(s, SIOCGIFGETRTREFCNT, (caddr_t)&ifr) != -1) {
+               ref = ifr.ifr_route_refcnt;
+       } else {
+               ref = INVALID_SOCKET_REF;
+       }
+       close(s);
+       return (ref);
+}
+
+
+__private_extern__
+void
+interface_update_idle_state(const char *if_name)
+{
+       CFStringRef             if_name_cf;
+       CFStringRef             key;
+       int                     ref;
+
+       /* We will only update the SCDynamicStore if the idle ref count
+        * is still 0 */
+       ref = socket_reference_count(if_name);
+       if (ref != 0) {
+               return;
+       }
+
+       if_name_cf = CFStringCreateWithCString(NULL, if_name,
+                                              kCFStringEncodingASCII);
+
+       key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+                                                           kSCDynamicStoreDomainState,
+                                                           if_name_cf,
+                                                           kSCEntNetIdleRoute);
+
+       cache_SCDynamicStoreNotifyValue(store, key);
+       CFRelease(key);
+       CFRelease(if_name_cf);
+       return;
+}
+#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
index 7e21623d9bcce65252bff7733f3fbee3d08e5937..f78ce84634512c685d42912f83873b152ad6eb64 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2004, 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002, 2004, 2005, 2011 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 __BEGIN_DECLS
 
-void   interface_detaching     (const char *if_name);
-void   link_add                (const char *if_name);
-void   link_remove             (const char *if_name);
-void   link_update_status      (const char *if_name, boolean_t attach);
+__private_extern__
+void   interface_detaching             (const char *if_name);
+
+__private_extern__
+void   interface_update_idle_state     (const char *if_name);
+
+__private_extern__
+void   interface_update_quality_metric (const char *if_name, int quality);
+
+__private_extern__
+void   link_add                        (const char *if_name);
+
+__private_extern__
+void   link_remove                     (const char *if_name);
+
+__private_extern__
+void   link_update_status              (const char *if_name, boolean_t attach);
 
 __END_DECLS
 
index 4f1c15fcef4471639443fc38e10eb5a552155090..14e2979db2089ed6156152b9a8f163cb45147dad 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2005, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2005, 2007, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -72,7 +72,7 @@ appendAddress(CFMutableDictionaryRef dict, CFStringRef key, struct in_addr *addr
 
 
 static CFMutableDictionaryRef
-getIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs)
+copyIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs)
 {
        CFDictionaryRef         dict            = NULL;
        CFMutableDictionaryRef  newDict         = NULL;
@@ -180,23 +180,28 @@ interface_update_ipv4(struct ifaddrs *ifap, const char *if_name)
                                                                          kSCEntNetIPv4);
                CFRelease(interface);
 
-               newDict = getIF(key, oldIFs, newIFs);
+               newDict = copyIF(key, oldIFs, newIFs);
 
-               sin = (struct sockaddr_in *)ifa->ifa_addr;
+               /* ALIGN: cast ok, this should be aligned (getifaddrs). */
+               sin = (struct sockaddr_in *)(void *)ifa->ifa_addr;
                appendAddress(newDict, kSCPropNetIPv4Addresses, &sin->sin_addr);
 
                if (ifa->ifa_flags & IFF_POINTOPOINT) {
                        struct sockaddr_in      *dst;
 
-                       dst = (struct sockaddr_in *)ifa->ifa_dstaddr;
+                       /* ALIGN: cast ok, this should be aligned (getifaddrs). */
+                       dst = (struct sockaddr_in *)(void *)ifa->ifa_dstaddr;
                        appendAddress(newDict, kSCPropNetIPv4DestAddresses, &dst->sin_addr);
                } else {
                        struct sockaddr_in      *brd;
                        struct sockaddr_in      *msk;
 
-                       brd = (struct sockaddr_in *)ifa->ifa_broadaddr;
-                       appendAddress(newDict, kSCPropNetIPv4BroadcastAddresses, &brd->sin_addr);
-                       msk = (struct sockaddr_in *)ifa->ifa_netmask;
+                       /* ALIGN: cast ok, this should be aligned (getifaddrs). */
+                       brd = (struct sockaddr_in *)(void *)ifa->ifa_broadaddr;
+                       appendAddress(newDict, kSCPropNetIPv4BroadcastAddresses,&brd->sin_addr);
+
+                       /* ALIGN: cast ok, this should be aligned (getifaddrs). */
+                       msk = (struct sockaddr_in *)(void *)ifa->ifa_netmask;
                        appendAddress(newDict, kSCPropNetIPv4SubnetMasks, &msk->sin_addr);
                }
 
@@ -214,7 +219,7 @@ interface_update_ipv4(struct ifaddrs *ifap, const char *if_name)
                                                                          kSCEntNetIPv4);
                CFRelease(interface);
 
-               newDict = getIF(key, oldIFs, newIFs);
+               newDict = copyIF(key, oldIFs, newIFs);
 
                CFDictionarySetValue(newIFs, key, newDict);
                CFRelease(newDict);
index 786cf095b9f8b90c6800939866ce587b62f69985..0e75b21a4b567c0f54bd342b5f29e4834a6c56bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2005, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2005, 2007, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 __BEGIN_DECLS
 
+__private_extern__
 void   interface_update_ipv4   (struct ifaddrs *ifap, const char *if_name);
+
+__private_extern__
 void   interface_collision_ipv4(const char *if_name,
                                 struct in_addr ip_addr,
                                 int hw_len, const void * hw_addr);
+
 #if    !TARGET_OS_IPHONE
-void   port_in_use_ipv4(uint16_t port, pid_t req_pid);
+__private_extern__
+void   port_in_use_ipv4        (uint16_t port, pid_t req_pid);
 #endif /* !TARGET_OS_IPHONE */
 
 __END_DECLS
index 880713a63e87fcfa574d857d3d3ad856f4ee35ee..abe37ff59596d268511764080e4e9623cc9787b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2007, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -185,7 +185,7 @@ appendScopeID(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6)
 
 
 static CFMutableDictionaryRef
-getIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs)
+copyIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs)
 {
        CFDictionaryRef         dict            = NULL;
        CFMutableDictionaryRef  newDict         = NULL;
@@ -308,12 +308,13 @@ interface_update_ipv6(struct ifaddrs *ifap, const char *if_name)
                                                                          kSCEntNetIPv6);
                CFRelease(interface);
 
-               newDict = getIF(key, oldIFs, newIFs);
+               newDict = copyIF(key, oldIFs, newIFs);
 
-               sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+               /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */
+               sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
 
                /* XXX: embedded link local addr check */
-               if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+               if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
                        u_int16_t       index;
 
                        index = sin6->sin6_addr.s6_addr16[1];
@@ -337,17 +338,20 @@ interface_update_ipv6(struct ifaddrs *ifap, const char *if_name)
 #ifdef NOTYET
                appendScopeID  (newDict, sin6);
 #endif /* NOTYET */
-               appendPrefixLen(newDict, (struct sockaddr_in6 *)ifa->ifa_netmask);
+               /* ALIGN: ifa should be aligned (from getifaddrs), cast ok.
+                * appendPrefixLen expect byte alignment */
+               appendPrefixLen(newDict, (struct sockaddr_in6 *)(void *)ifa->ifa_netmask);
                appendFlags    (newDict, flags6);
 
 
                if (ifa->ifa_flags & IFF_POINTOPOINT) {
                        struct sockaddr_in6     *dst6;
 
-                       dst6 = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
+                       /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */
+                       dst6 = (struct sockaddr_in6 *)(void *)ifa->ifa_dstaddr;
 
                        /* XXX: embedded link local addr check */
-                       if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) {
+                       if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6->sin6_addr)) {
                                u_int16_t       index;
 
                                index = dst6->sin6_addr.s6_addr16[1];
@@ -376,7 +380,7 @@ interface_update_ipv6(struct ifaddrs *ifap, const char *if_name)
                                                                          kSCEntNetIPv6);
                CFRelease(interface);
 
-               newDict = getIF(key, oldIFs, newIFs);
+               newDict = copyIF(key, oldIFs, newIFs);
 
                CFDictionarySetValue(newIFs, key, newDict);
                CFRelease(newDict);
index 23f1ced448b1b57cf4cecf345ff9577969a7405a..4cdd37803f673e98ba3b74785c07b82a3883e3d1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002, 2004, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -36,6 +36,7 @@
 
 __BEGIN_DECLS
 
+__private_extern__
 void   interface_update_ipv6   (struct ifaddrs *ifap, const char *if_name);
 
 __END_DECLS
index 10792c0b517f63bbde03bd910511b0c5e42caf7a..c2cad274232cbc7d19cd99bfdd07c86709d001c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -96,7 +96,13 @@ static const char *dlEventName[] = {
        "KEV_DL_WAKEFLAGS_CHANGED",
 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
        "KEV_DL_IF_IDLE_ROUTE_REFCNT",
-#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
+#endif
+#ifdef  KEV_DL_IFCAP_CHANGED
+       "KEV_DL_IFCAP_CHANGED",
+#endif
+#ifdef  KEV_DL_LINK_QUALITY_METRIC_CHANGED
+       "KEV_DL_LINK_QUALITY_METRIC_CHANGED",
+#endif
 };
 
 static const char *inet6EventName[] = {
@@ -109,6 +115,13 @@ static const char *inet6EventName[] = {
        "KEV_INET6_DEFROUTER"
 };
 
+#ifdef KEV_ND6_SUBCLASS
+static const char *nd6EventNameString[] = {
+       "",
+       "KEV_ND6_RA"
+};
+#endif // KEV_ND6_SUBCLASS
+
 __private_extern__ Boolean             network_changed = FALSE;
 __private_extern__ SCDynamicStoreRef   store           = NULL;
 __private_extern__ Boolean             _verbose        = FALSE;
@@ -398,6 +411,21 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg)
                                        break;
                                }
 
+#ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
+                               case KEV_DL_IF_IDLE_ROUTE_REFCNT: {
+                                       /*
+                                        * interface route refcnt idle
+                                        */
+                                       if (dataLen < sizeof(*ev)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(ev, ifr_name, sizeof(ifr_name));
+                                       interface_update_idle_state(ifr_name);
+                                       break;
+                               }
+#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
+
                                case KEV_DL_LINK_OFF :
                                case KEV_DL_LINK_ON :
                                        /*
@@ -411,6 +439,22 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg)
                                        link_update_status(ifr_name, FALSE);
                                        break;
 
+#ifdef  KEV_DL_LINK_QUALITY_METRIC_CHANGED
+                               case KEV_DL_LINK_QUALITY_METRIC_CHANGED: {
+                                       struct kev_dl_link_quality_metric_data * lqm_data;
+                                       lqm_data = (struct kev_dl_link_quality_metric_data *) event_data;
+
+                                       if (dataLen < sizeof(*ev)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(ev, ifr_name, sizeof(ifr_name));
+                                       interface_update_quality_metric(ifr_name,
+                                                                  lqm_data->link_quality_metric);
+                                       break;
+                               }
+#endif  // KEV_DL_LINK_QUALITY_METRIC_CHANGED
+
                                case KEV_DL_SIFFLAGS :
                                case KEV_DL_SIFMETRICS :
                                case KEV_DL_SIFMTU :
@@ -421,9 +465,22 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg)
                                case KEV_DL_DELMULTI :
                                case KEV_DL_LINK_ADDRESS_CHANGED :
                                case KEV_DL_WAKEFLAGS_CHANGED :
-#ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
-                               case KEV_DL_IF_IDLE_ROUTE_REFCNT :
-#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
+#ifdef  KEV_DL_IFCAP_CHANGED
+                               case KEV_DL_IFCAP_CHANGED :
+#endif // KEV_DL_IFCAP_CHANGED
+                                       break;
+
+                               default :
+                                       handled = FALSE;
+                                       break;
+                       }
+                       break;
+               }
+#ifdef KEV_ND6_SUBCLASS
+               case KEV_ND6_SUBCLASS : {
+                       eventName = nd6EventNameString(ev_msg->event_code);
+                       switch (ev_msg->event_code) {
+                               case KEV_KEV_ND6_RA :
                                        break;
 
                                default :
@@ -432,6 +489,7 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg)
                        }
                        break;
                }
+#endif // KEV_ND6_SUBCLASS
                case KEV_LOG_SUBCLASS : {
                        break;
                }
@@ -457,8 +515,11 @@ eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const
 {
        int                     so              = CFSocketGetNative(s);
        int                     status;
-       char                    buf[1024];
-       struct kern_event_msg   *ev_msg         = (struct kern_event_msg *)&buf[0];
+       union {
+               char                    bytes[1024];
+               struct kern_event_msg   ev_msg1;        // first kernel event
+       } buf;
+       struct kern_event_msg   *ev_msg         = &buf.ev_msg1;
        int                     offset          = 0;
 
        status = recv(so, &buf, sizeof(buf), 0);
@@ -499,7 +560,7 @@ eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const
                                break;
                }
                offset += ev_msg->total_size;
-               ev_msg = (struct kern_event_msg *)&buf[offset];
+               ev_msg = (struct kern_event_msg *)(void *)&buf.bytes[offset];
        }
 
        cache_write(store);
index c9a81c05ed7f0b7704b5bb86931bcd2eaf6b91bf..af70ff1dbcf05ccebf7ab2f13f2d3f93ac25bed0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2004, 2005, 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2002, 2004, 2005, 2007, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -63,6 +63,7 @@ extern Boolean                        _verbose;
 
 __BEGIN_DECLS
 
+__private_extern__
 int    dgram_socket            (int    domain);
 
 __END_DECLS
index 30e9f1d42bf667619ace6f47f39c9d60def15f4c..f3cbe7b6f27001cde514cf8b40314b925869c4dd 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>Requires</key>
        <array>
                <string>com.apple.SystemConfiguration.InterfaceNamer</string>
index 3f73f2ee85a3c4cede4b9c91f0a8b942ed1627b1..619bac49946b98cc191674b41f1f55a739309711 100644 (file)
@@ -442,7 +442,7 @@ _SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef     interface,
  * 2. key = "a/b/c" prefix = "a/b/"
  *    returns "c"
  */
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 parse_component(CFStringRef key, CFStringRef prefix)
 {
        CFMutableStringRef      comp;
index be01e39a05faba8ef0195b6f742929629c9d0738..295de0b16ec08a4d153ff140ac9c84914a5fcb6d 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>Enabled</key>
        <false/>
        <key>Verbose</key>
@@ -30,6 +30,8 @@
        <true/>
        <key>LOG_NETWORK_KERNEL_EVENTS</key>
        <false/>
+       <key>LOG_NETWORK_INFORMATION</key>
+       <true/>
        <key>LOG_NOTIFY_DNS_CONFIGURATION</key>
        <true/>
        <key>LOG_NOTIFY_NETWORK_CHANGE</key>
@@ -44,5 +46,9 @@
        <array>
                <string>mail.me.com</string>
        </array>
+       <key>Requires</key>
+       <array>
+               <string>com.apple.SystemConfiguration.SCNetworkReachability</string>
+       </array>
 </dict>
 </plist>
index 5247be22d5b486f6fafe000def037e1ee501c20a..440c296de1768146609827ff5bf32ff837a5d79c 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>Enabled</key>
        <false/>
        <key>Verbose</key>
@@ -32,6 +32,8 @@
        <false/>
        <key>LOG_NETWORK_KERNEL_EVENTS</key>
        <true/>
+       <key>LOG_NETWORK_INFORMATION</key>
+       <true/>
        <key>LOG_NOTIFY_DNS_CONFIGURATION</key>
        <true/>
        <key>LOG_NOTIFY_NETWORK_CHANGE</key>
@@ -56,5 +58,9 @@
        <array>
                <string>mail.me.com</string>
        </array>
+       <key>Requires</key>
+       <array>
+               <string>com.apple.SystemConfiguration.SCNetworkReachability</string>
+       </array>
 </dict>
 </plist>
index 489734c7d025ef48e6f24f33bc216de7bc00e58a..81b7c6ee446e9c5fc886ce3cdc1c05145dbfa8cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -35,6 +35,7 @@
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <net/ethernet.h>
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
@@ -58,6 +59,7 @@
 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
 
 #include <dnsinfo.h>
+#include <network_information.h>
 #include <notify.h>
 #if    (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) && !TARGET_OS_EMBEDDED
 #include <utmpx.h>
@@ -211,8 +213,11 @@ KernelEvent_notification(CFSocketRef s, CFSocketCallBackType type, CFDataRef add
 {
        int                     so              = CFSocketGetNative(s);
        int                     status;
-       char                    buf[1024];
-       struct kern_event_msg   *ev_msg         = (struct kern_event_msg *)&buf[0];
+       union {
+               char                    bytes[1024];
+               struct kern_event_msg   ev_msg1;        // first kernel event
+       } buf;
+       struct kern_event_msg   *ev_msg         = &buf.ev_msg1;
        int                     offset          = 0;
 
        status = recv(so, &buf, sizeof(buf), 0);
@@ -435,7 +440,7 @@ KernelEvent_notification(CFSocketRef s, CFSocketCallBackType type, CFDataRef add
                                break;
                }
                offset += ev_msg->total_size;
-               ev_msg = (struct kern_event_msg *)&buf[offset];
+               ev_msg = (struct kern_event_msg *)(void *)&buf.bytes[offset];
        }
 
        return;
@@ -689,68 +694,171 @@ static void
 NetworkChange_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
 {
        CFIndex                 i;
-       CFIndex                 n;
-       CFMutableStringRef      str     = CFStringCreateMutable(NULL, 0);
+       CFIndex                 nk;
+       CFMutableStringRef      str;
 
+       str = CFStringCreateMutable(NULL, 0);
        CFStringAppendFormat(str,
                             NULL,
                             CFSTR("%s SCDynamicStore \"network\" notification"),
                             elapsed());
 
-       n = CFArrayGetCount(changedKeys);
-       for (i = 0; i < n; i++) {
+       nk = CFArrayGetCount(changedKeys);
+       for (i = 0; i < nk; i++) {
+               CFArrayRef      components;
                CFStringRef     key;
+               CFIndex         nc;
 
                key = CFArrayGetValueAtIndex(changedKeys, i);
-               if (CFStringHasSuffix(key, kSCEntNetLink)) {
-                       CFDictionaryRef dict;
-                       const char      *val    = "?";
 
-                       dict = SCDynamicStoreCopyValue(store, key);
-                       if (dict != NULL) {
-                               CFBooleanRef    link;
+               components = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
+               if (components == NULL) {
+                       CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
+                       continue;
+               }
 
-                               link = CFDictionaryGetValue(dict, kSCPropNetLinkActive);
-                               if (link != NULL) {
-                                       val = CFBooleanGetValue(link) ? "up" : "down";
-                               }
+               nc = CFArrayGetCount(components);
+               switch (nc) {
+                       case 5 : {
+                               CFStringRef     entity_id;
 
-                               CFRelease(dict);
+                               entity_id  = CFArrayGetValueAtIndex(components, 4);
+                               if (CFEqual(entity_id, kSCEntNetLink)) {
+                                       CFDictionaryRef dict;
+                                       const char      *val    = "?";
+
+                                       dict = SCDynamicStoreCopyValue(store, key);
+                                       if (dict != NULL) {
+                                               CFBooleanRef    link;
+
+                                               link = CFDictionaryGetValue(dict, kSCPropNetLinkActive);
+                                               if (link != NULL) {
+                                                       val = CFBooleanGetValue(link) ? "up" : "down";
+                                               }
+
+                                               CFRelease(dict);
+                                       }
+                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@ (%s)"), key, val);
+                               } else if (CFEqual(entity_id, kSCEntNetIPv4) ||
+                                          CFEqual(entity_id, kSCEntNetIPv6) ||
+                                          CFEqual(entity_id, kSCEntNetDNS)) {
+                                       CFDictionaryRef dict;
+
+                                       dict = SCDynamicStoreCopyValue(store, key);
+                                       if (dict != NULL) {
+                                               CFStringRef     val;
+
+                                               val = _SCCopyDescription(dict, NULL);
+                                               CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val);
+                                               CFRelease(val);
+                                               CFRelease(dict);
+                                       } else {
+                                               CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
+                                       }
+                               } else if (CFEqual(entity_id, kSCEntNetAirPort)) {
+                                       CFDictionaryRef dict;
+
+                                       dict = SCDynamicStoreCopyValue(store, key);
+                                       if (dict != NULL) {
+                                               CFStringRef     ssid_str;
+
+                                               ssid_str = CFDictionaryGetValue(dict, CFSTR("SSID_STR"));
+                                               if (ssid_str != NULL) {
+                                                       CFDataRef       bssid;
+
+                                                       bssid = CFDictionaryGetValue(dict, CFSTR("BSSID"));
+                                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@ : SSID: %@ BSSID: %s"),
+                                                                            key,
+                                                                            ssid_str,
+                                                                            (bssid != NULL) ? ether_ntoa((struct ether_addr *)CFDataGetBytePtr(bssid)) : "<unknown>");
+                                               } else {
+                                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@ : no SSID"), key);
+                                               }
+                                               CFRelease(dict);
+                                       } else {
+                                               CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
+                                       }
+                               } else if (CFEqual(entity_id, kSCEntNetService)) {
+                                       CFDictionaryRef dict;
+                                       CFStringRef     rank    = kSCNetworkServicePrimaryRankDefault;
+
+                                       dict = SCDynamicStoreCopyValue(store, key);
+                                       if ((dict == NULL) ||
+                                           !CFDictionaryGetValueIfPresent(dict,
+                                                                          kSCPropNetServicePrimaryRank,
+                                                                          (const void **)&rank)) {
+                                               rank = kSCNetworkServicePrimaryRankDefault;
+                                       }
+                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@ : Rank = %@"), key, rank);
+                                       if (dict != NULL) CFRelease(dict);
+                               } else {
+                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
+                               }
+                               break;
                        }
-                       CFStringAppendFormat(str, NULL, CFSTR("\n%@ (%s)"), key, val);
-               } else if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
-                          CFStringHasSuffix(key, kSCEntNetIPv6) ||
-                          CFStringHasSuffix(key, kSCEntNetDNS)) {
-                       CFDictionaryRef dict;
-
-                       dict = SCDynamicStoreCopyValue(store, key);
-                       if (dict != NULL) {
-                               CFStringRef     val;
-
-                               val = _SCCopyDescription(dict, NULL);
-                               CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val);
-                               CFRelease(val);
-                               CFRelease(dict);
-                       } else {
-                               CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
+
+                       case 4 : {
+                               static CFStringRef      rank_setup_prefix       = NULL;
+                               static CFStringRef      rank_state_prefix       = NULL;
+
+                               if (rank_setup_prefix == NULL) {
+                                       rank_setup_prefix = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                                                                       kSCDynamicStoreDomainSetup,
+                                                                                                       CFSTR(""),
+                                                                                                       NULL);
+                                       rank_state_prefix = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                                                                       kSCDynamicStoreDomainState,
+                                                                                                       CFSTR(""),
+                                                                                                       NULL);
+                               }
+
+                               if (CFStringHasPrefix(key, rank_setup_prefix) ||
+                                   CFStringHasPrefix(key, rank_state_prefix)) {
+                                       CFDictionaryRef dict;
+                                       CFStringRef     rank    = kSCNetworkServicePrimaryRankDefault;
+
+                                       dict = SCDynamicStoreCopyValue(store, key);
+                                       if ((dict == NULL) ||
+                                           !CFDictionaryGetValueIfPresent(dict,
+                                                                          kSCPropNetServicePrimaryRank,
+                                                                          (const void **)&rank)) {
+                                               rank = kSCNetworkServicePrimaryRankDefault;
+                                       }
+                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@ : Rank = %@"), key, rank);
+                                       if (dict != NULL) CFRelease(dict);
+                               } else {
+                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
+                               }
+                               break;
                        }
-               } else if (CFStringHasSuffix(key, CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix))) {
-                       CFNumberRef     num;
 
-                       num = SCDynamicStoreCopyValue(store, key);
-                       if (num != NULL) {
-                               IOPMSystemPowerStateCapabilities        capabilities;
+                       case 2 :
+                               if (CFEqual(CFArrayGetValueAtIndex(components, 1),
+                                           CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix))) {
+                                       CFNumberRef     num;
 
-                               if (isA_CFNumber(num) &&
-                                   CFNumberGetValue(num, kCFNumberSInt32Type, &capabilities)) {
-                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@ (0x%x)"), key, capabilities);
+                                       num = SCDynamicStoreCopyValue(store, key);
+                                       if (num != NULL) {
+                                               IOPMSystemPowerStateCapabilities        capabilities;
+
+                                               if (isA_CFNumber(num) &&
+                                                   CFNumberGetValue(num, kCFNumberSInt32Type, &capabilities)) {
+                                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@ (0x%x)"), key, capabilities);
+                                               }
+
+                                               CFRelease(num);
+                                       }
+                               } else {
+                                       CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
                                }
+                               break;
 
-                               CFRelease(num);
-                       }
-               } else {
-                       CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
+                       default :
+                               CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
+                               break;
                }
+
+               CFRelease(components);
        }
 
        SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
@@ -759,6 +867,47 @@ NetworkChange_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void
 }
 
 
+static void
+add_NetworkChange_keys(CFMutableArrayRef       keys,
+                      CFMutableArrayRef        patterns,
+                      CFStringRef              entity,
+                      Boolean                  doGlobal,
+                      Boolean                  doService,
+                      Boolean                  doInterface)
+{
+       CFStringRef     key;
+       CFStringRef     pattern;
+
+       if (doGlobal) {
+               key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainSetup, entity);
+               CFArrayAppendValue(keys, key);
+               CFRelease(key);
+
+               key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, entity);
+               CFArrayAppendValue(keys, key);
+               CFRelease(key);
+       }
+
+       if (doService) {
+               pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, entity);
+               CFArrayAppendValue(patterns, pattern);
+               CFRelease(pattern);
+
+               pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, entity);
+               CFArrayAppendValue(patterns, pattern);
+               CFRelease(pattern);
+       }
+
+       if (doInterface) {
+               pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, entity);
+               CFArrayAppendValue(patterns, pattern);
+               CFRelease(pattern);
+       }
+
+       return;
+}
+
+
 static void
 add_NetworkChange_notification()
 {
@@ -766,7 +915,6 @@ add_NetworkChange_notification()
        CFStringRef             key;
        CFMutableArrayRef       keys;
        Boolean                 ok;
-       CFStringRef             pattern;
        CFMutableArrayRef       patterns;
        SCDynamicStoreRef       store;
        CFRunLoopSourceRef      rls;
@@ -788,67 +936,31 @@ add_NetworkChange_notification()
 
        // IPv4
 
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
-       CFArrayAppendValue(keys, key);
-       CFRelease(key);
-
-       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
-
-       pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetIPv4, TRUE, TRUE, TRUE);
 
        // IPv6
 
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
-       CFArrayAppendValue(keys, key);
-       CFRelease(key);
-
-       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
-
-       pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetIPv6, TRUE, TRUE, TRUE);
 
        // PPP, VPN
 
-       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetPPP);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
-
-       pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetPPP);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
-
-       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetVPN);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
-
-       pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetVPN);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetPPP,   FALSE, TRUE, TRUE);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetVPN,   FALSE, TRUE, TRUE);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetL2TP,  FALSE, TRUE, TRUE);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetPPTP,  FALSE, TRUE, TRUE);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetIPSec, FALSE, TRUE, TRUE);
 
        // Link
 
-       pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetLink);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetLink, FALSE, FALSE, TRUE);
 
        // AirPort (e.g. BSSID)
 
-       pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetAirPort);
-       CFArrayAppendValue(patterns, pattern);
-       CFRelease(pattern);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetAirPort, FALSE, FALSE, TRUE);
 
        // DNS
 
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
-       CFArrayAppendValue(keys, key);
-       CFRelease(key);
+       add_NetworkChange_keys(keys, patterns, kSCEntNetDNS, TRUE, TRUE, TRUE);
 
        dns_key = CFStringCreateWithCString(NULL,
                                            dns_configuration_notify_key(),
@@ -864,6 +976,11 @@ add_NetworkChange_notification()
        CFArrayAppendValue(keys, key);
        CFRelease(key);
 
+       // Rank
+
+       add_NetworkChange_keys(keys, patterns, NULL, FALSE, TRUE, FALSE);               // per-service
+       add_NetworkChange_keys(keys, patterns, kSCEntNetService, FALSE, FALSE, TRUE);   // per-interface
+
        // ComputerName, LocalHostName
 
        key = SCDynamicStoreKeyCreateComputerName(NULL);
@@ -874,12 +991,17 @@ add_NetworkChange_notification()
        CFArrayAppendValue(keys, key);
        CFRelease(key);
 
+       // Power Management
+
        key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@%@"),
                                      kSCDynamicStoreDomainState,
                                      CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix));
        CFArrayAppendValue(keys, key);
        CFRelease(key);
 
+
+       // Setup monitoring
+
        ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
        CFRelease(keys);
        CFRelease(patterns);
@@ -1332,6 +1454,60 @@ add_dnsinfo_notification()
 }
 
 
+#pragma mark -
+#pragma mark Network Information Events
+
+
+static void
+nwi_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
+{
+       SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
+             CFSTR("%s network_information notification"),
+             elapsed());
+
+       return;
+}
+
+
+static void
+add_nwi_notification()
+{
+       const char              *key;
+       CFMachPortRef           mp;
+       mach_port_t             notify_port;
+       int                     notify_token;
+       CFRunLoopSourceRef      rls;
+       uint32_t                status;
+
+       key = nwi_state_get_notify_key();
+       status = notify_register_mach_port(key, &notify_port, 0, &notify_token);
+       if (status != NOTIFY_STATUS_OK) {
+               SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
+               return;
+       }
+
+       mp = _SC_CFMachPortCreateWithPort("Logger/nwi", notify_port, nwi_notification, NULL);
+       if (mp == NULL) {
+               SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
+               (void)notify_cancel(notify_token);
+               return;
+       }
+
+       rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
+       if (rls == NULL) {
+               SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
+               CFRelease(mp);
+               (void)notify_cancel(notify_token);
+               return;
+       }
+       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+       CFRelease(rls);
+
+       CFRelease(mp);
+       return;
+}
+
+
 #pragma mark -
 #pragma mark Network Configuration Change Events
 
@@ -1792,6 +1968,10 @@ load(CFBundleRef bundle, Boolean bundleVerbose)
                add_KernelEvent_notification();
        }
 
+       if (log_all || bValFromDictionary(config, CFSTR("LOG_NETWORK_INFORMATION"))) {
+               add_nwi_notification();
+       }
+
        if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_DNS_CONFIGURATION"))) {
                add_dnsinfo_notification();
        }
diff --git a/Plugins/NetworkIdentification/Info.plist b/Plugins/NetworkIdentification/Info.plist
deleted file mode 100644 (file)
index e8e42f5..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>English</string>
-       <key>CFBundleExecutable</key>
-       <string>NetworkIdentification</string>
-       <key>CFBundleIdentifier</key>
-       <string>com.apple.SystemConfiguration.NetworkIdentification</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>com.apple.SystemConfiguration.NetworkIdentification</string>
-       <key>CFBundlePackageType</key>
-       <string>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
-       <key>CFBundleSignature</key>
-       <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1.11</string>
-       <key>Builtin</key>
-       <true/>
-</dict>
-</plist>
diff --git a/Plugins/NetworkIdentification/Makefile b/Plugins/NetworkIdentification/Makefile
deleted file mode 100644 (file)
index 1220f47..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-netsig: NetworkIdentification.c
-       cc -Wall -g -DTEST_NETWORKIDENTIFICATION -o netsig NetworkIdentification.c -framework CoreFoundation -framework SystemConfiguration
-
-clean:
-       rm -f netsig
-
diff --git a/Plugins/NetworkIdentification/NetworkIdentification.c b/Plugins/NetworkIdentification/NetworkIdentification.c
deleted file mode 100644 (file)
index 3f5ad51..0000000
+++ /dev/null
@@ -1,1235 +0,0 @@
-/*
- * Copyright (c) 2005-2007, 2009 Apple Inc.  All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * NetworkIdentification.c
- * - maintains a history of networks that the system has connected to by
- *   watching the Network Services that post data to the SCDynamicStore
- */
-
-/* 
- * Modification History
- *
- * November 9, 2006    Dieter Siegmund (dieter@apple.com)
- * - created
- */
-
-#include <notify.h>
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCValidation.h>
-#include <SystemConfiguration/SCPrivate.h>
-#include <CoreFoundation/CFDictionary.h>
-#include <SystemConfiguration/SCNetworkSignature.h>
-#include <SystemConfiguration/SCNetworkSignaturePrivate.h>
-
-/* debug output on/off */
-static Boolean                 S_NetworkIdentification_debug;
-
-/* should we bother keeping track of networks? */
-static Boolean                 S_NetworkIdentification_disabled;
-
-typedef struct ServiceWatcher_s ServiceWatcher, * ServiceWatcherRef;
-
-/* returns an array of currently available information */
-static CFArrayRef
-ServiceWatcherCopyCurrent(ServiceWatcherRef watcher);
-
-static ServiceWatcherRef
-ServiceWatcherCreate();
-
-static void
-ServiceWatcherFree(ServiceWatcherRef * watcher_p);
-
-/* XXX these should be made tunable */
-#define SIGNATURE_HISTORY_MAX                  150
-#define SERVICE_HISTORY_MAX                    5
-
-/* don't re-write the prefs file unless this time interval has elapsed */
-#define SIGNATURE_UPDATE_INTERVAL_SECS (24 * 3600) /* 24 hours */
-
-struct ServiceWatcher_s {
-    CFRunLoopSourceRef         rls;
-    SCDynamicStoreRef          store;
-    CFMutableArrayRef          signatures;
-    CFArrayRef                 active_signatures;
-    CFStringRef                        primary_ipv4;
-    CFStringRef                        setup_ipv4_key;
-    CFStringRef                        state_ipv4_key;
-};
-
-#define kIdentifier            CFSTR("Identifier")
-#define kService               CFSTR("Service")
-#define kServices              CFSTR("Services")
-#define kSignature             CFSTR("Signature")
-#define kSignatures            CFSTR("Signatures")
-#define kTimestamp             CFSTR("Timestamp")
-#define kServiceID             CFSTR("ServiceID")
-#define kNetworkSignature      CFSTR("NetworkSignature")
-#define kServiceIdentifiers    kStoreKeyServiceIdentifiers
-
-static CFArrayRef
-make_service_entity_pattern_array(CFStringRef * keys, int n_keys)
-{
-    int                i;
-    CFArrayRef list;
-
-    for (i = 0; i < n_keys; i++) {
-       /* re-use the array that was passed in to get the pattern */
-       keys[i] = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 
-                                                             kSCDynamicStoreDomainState,
-                                                             kSCCompAnyRegex,
-                                                             keys[i]);
-    }
-    list = CFArrayCreate(NULL, (const void * *)keys, n_keys,
-                        &kCFTypeArrayCallBacks);
-    for (i = 0; i < n_keys; i++) {
-       /* then release the allocated patterns */
-       CFRelease(keys[i]);
-    }
-    return (list);
-}
-
-static CFArrayRef
-ServiceWatcherNotificationPatterns(void)
-{
-    CFStringRef        keys[1] = { kSCEntNetIPv4 };
-    
-    return (make_service_entity_pattern_array(keys, 
-                                             sizeof(keys) / sizeof(keys[0])));
-}
-
-static CFArrayRef
-ServiceWatcherPatterns(void)
-{
-    CFStringRef        keys[2] = { kSCEntNetIPv4, kSCEntNetDNS };
-    
-    return (make_service_entity_pattern_array(keys,
-                                             sizeof(keys) / sizeof(keys[0])));
-}
-
-static CFTypeRef
-myCFDictionaryArrayGetValue(CFArrayRef array, CFStringRef key, CFTypeRef value,
-                           int * ret_index)
-{
-    int        count = 0;
-    int                i;
-
-    if (array != NULL) {
-       count = CFArrayGetCount(array);
-    }
-    if (count == 0) {
-       goto done;
-    }
-    for (i = 0; i < count; i++) {
-       CFDictionaryRef         dict;
-       CFTypeRef               this_val;
-
-       dict = CFArrayGetValueAtIndex(array, i);
-       if (isA_CFDictionary(dict) == NULL) {
-           continue;
-       }
-       this_val = CFDictionaryGetValue(dict, key);
-       if (CFEqual(this_val, value)) {
-           if (ret_index != NULL) {
-               *ret_index = i;
-           }
-           return (dict);
-       }
-    }
- done:
-    if (ret_index != NULL) {
-       *ret_index = -1;
-    }
-    return (NULL);
-}
-
-static CFDictionaryRef
-copy_airport_dict(SCDynamicStoreRef store, CFStringRef if_name)
-{
-    CFDictionaryRef    dict;
-    CFStringRef                key;
-
-    key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 
-                                                       kSCDynamicStoreDomainState,
-                                                       if_name,
-                                                       kSCEntNetAirPort);
-    dict = SCDynamicStoreCopyValue(store, key);
-    CFRelease(key);
-    return (dict);
-}
-
-static void
-add_airport_info(SCDynamicStoreRef store, CFMutableDictionaryRef dict)
-{
-    CFDictionaryRef    airport_dict = NULL;
-    CFStringRef                key;
-    CFStringRef                if_name;
-    CFDictionaryRef    simple_dict;
-    CFStringRef                value;
-
-    if_name = CFDictionaryGetValue(dict, kSCPropInterfaceName);
-    if (isA_CFString(if_name) == NULL) {
-       goto done;
-    }
-    airport_dict = copy_airport_dict(store, if_name);
-    if (airport_dict == NULL) {
-       goto done;
-    }
-    key = CFSTR("SSID");
-    value = CFDictionaryGetValue(airport_dict, key);
-    if (value == NULL) {
-       goto done;
-    }
-    simple_dict =
-       CFDictionaryCreate(NULL, 
-                          (const void * *)&key, (const void * *)&value, 1, 
-                          &kCFTypeDictionaryKeyCallBacks,
-                          &kCFTypeDictionaryValueCallBacks);
-    CFDictionarySetValue(dict, kSCEntNetAirPort, simple_dict);
-    CFRelease(simple_dict);
-
- done:
-    if (airport_dict != NULL) {
-       CFRelease(airport_dict);
-    }
-    return;
-}
-
-static CFDictionaryRef
-get_current_dict(CFDictionaryRef current, CFStringRef entity,
-                CFArrayRef components)
-{
-    CFDictionaryRef    dict;
-    CFStringRef                key;
-
-    if (CFArrayGetCount(components) < 5) {
-       /* this can't happen, we already checked */
-       return (NULL);
-    }
-    key = CFStringCreateWithFormat(NULL, NULL,
-                                  CFSTR("%@/%@/%@/%@/%@"),
-                                  CFArrayGetValueAtIndex(components, 0),
-                                  CFArrayGetValueAtIndex(components, 1),
-                                  CFArrayGetValueAtIndex(components, 2),
-                                  CFArrayGetValueAtIndex(components, 3),
-                                  entity);
-    dict = CFDictionaryGetValue(current, key);
-    CFRelease(key);
-    return (isA_CFDictionary(dict));
-}
-
-static CFArrayRef
-process_dict(SCDynamicStoreRef store, CFDictionaryRef current)
-{
-    CFMutableArrayRef          array = NULL;
-    int                                count = 0;
-    int                                i;
-    const void * *             keys = NULL;
-    const void * *             values = NULL;
-
-    count = CFDictionaryGetCount(current);
-    if (count == 0) {
-       goto done;
-    }
-    array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    keys = (const void * *)malloc(sizeof(keys) * count);
-    values = (const void * *)malloc(sizeof(values) * count);
-    CFDictionaryGetKeysAndValues(current, keys, values);
-    for (i = 0; i < count; i++) {
-       CFArrayRef              components = NULL;
-       CFDictionaryRef         dns_dict;
-       CFStringRef             entity;
-       CFMutableDictionaryRef  entity_dict = NULL;
-       CFMutableDictionaryRef  new_dict = NULL;
-       CFStringRef             sig_str = NULL;
-       CFMutableDictionaryRef  service_dict = NULL;
-       CFStringRef             serviceID;
-       
-       if (isA_CFDictionary(values[i]) == NULL) {
-           goto loop_done;
-       }
-       components = CFStringCreateArrayBySeparatingStrings(NULL, keys[i],
-                                                           CFSTR("/"));
-       if (components == NULL) {
-           goto loop_done;
-       }
-       if (CFArrayGetCount(components) < 5) {
-           /* too few components */
-           goto loop_done;
-       }
-       entity = CFArrayGetValueAtIndex(components, 4);
-       if (!CFEqual(entity, kSCEntNetIPv4)) {
-           goto loop_done;
-       }
-       serviceID = CFArrayGetValueAtIndex(components, 3);
-       sig_str = CFDictionaryGetValue(values[i], kNetworkSignature);
-       if (isA_CFString(sig_str) == NULL
-           || CFStringGetLength(sig_str) == 0) {
-           goto loop_done;
-       }
-       /* create a new entry */
-       new_dict = CFDictionaryCreateMutable(NULL, 0, 
-                                            &kCFTypeDictionaryKeyCallBacks,
-                                            &kCFTypeDictionaryValueCallBacks);
-       CFDictionarySetValue(new_dict, kSignature, sig_str);
-       service_dict = CFDictionaryCreateMutable(NULL, 0, 
-                                                &kCFTypeDictionaryKeyCallBacks,
-                                                &kCFTypeDictionaryValueCallBacks);
-       CFDictionarySetValue(service_dict, kServiceID, serviceID);
-       add_airport_info(store, service_dict);
-       entity_dict = CFDictionaryCreateMutableCopy(NULL, 0, values[i]);
-       CFDictionaryRemoveValue(entity_dict, kNetworkSignature);
-       CFDictionarySetValue(service_dict, kSCEntNetIPv4, entity_dict);
-       dns_dict = get_current_dict(current, kSCEntNetDNS, components);
-       if (dns_dict != NULL) {
-           CFDictionarySetValue(service_dict, kSCEntNetDNS, dns_dict);
-       }
-       CFDictionarySetValue(new_dict, kService, service_dict);
-       CFArrayAppendValue(array, new_dict);
-
-    loop_done:
-       if (entity_dict != NULL) {
-           CFRelease(entity_dict);
-       }
-       if (service_dict != NULL) {
-           CFRelease(service_dict);
-       }
-       if (components != NULL) {
-           CFRelease(components);
-       }
-       if (new_dict != NULL) {
-           CFRelease(new_dict);
-       }
-    }
-    count = CFArrayGetCount(array);
-    if (count == 0) {
-       CFRelease(array);
-       array = NULL;
-       goto done;
-    }
-
- done:
-    if (keys != NULL) {
-       free(keys);
-    }
-    if (values != NULL) {
-       free(values);
-    }
-    return (array);
-
-}
-
-static CFArrayRef
-ServiceWatcherCopyCurrent(ServiceWatcherRef watcher)
-{
-    CFDictionaryRef    current;
-    CFArrayRef         list;
-    CFArrayRef         ret = NULL;
-    
-    list = ServiceWatcherPatterns();
-    current = SCDynamicStoreCopyMultiple(watcher->store, NULL, list);
-    CFRelease(list);
-    if (current == NULL) {
-       goto done;
-    }
-    ret = process_dict(watcher->store, current);
- done:
-    if (current != NULL) {
-       CFRelease(current);
-    }
-    return (ret);
-}
-
-static Boolean
-ServiceWatcherSetActiveSignatures(ServiceWatcherRef watcher, CFArrayRef active)
-{
-    Boolean    changed = FALSE;
-    CFArrayRef prev_active;
-
-    prev_active = watcher->active_signatures;
-    if (prev_active == NULL && active == NULL) {
-       /* nothing to do */
-       goto done;
-    }
-    if (prev_active != NULL && active != NULL) {
-       changed = !CFEqual(prev_active, active);
-    }
-    else {
-       changed = TRUE;
-    }
-    if (active != NULL) {
-       CFRetain(active);
-    }
-    if (prev_active != NULL) {
-       CFRelease(prev_active);
-    }
-    watcher->active_signatures = active;
-    if (changed) {
-       if (active != NULL) {
-           SCLog(S_NetworkIdentification_debug,
-                 LOG_NOTICE, CFSTR("Active Signatures %@"), active);
-       }
-       else {
-           SCLog(S_NetworkIdentification_debug,
-                 LOG_NOTICE, CFSTR("No Active Signatures"));
-       }
-    }
- done:
-    return (changed);
-}
-
-static Boolean
-ServiceWatcherSetPrimaryIPv4(ServiceWatcherRef watcher,
-                            CFStringRef primary_ipv4)
-{
-    Boolean            changed = FALSE;
-    CFStringRef                prev_ipv4_primary;
-
-    prev_ipv4_primary = watcher->primary_ipv4;
-    if (prev_ipv4_primary == NULL && primary_ipv4 == NULL) {
-       /* nothing to do */
-       goto done;
-    }
-    if (prev_ipv4_primary != NULL && primary_ipv4 != NULL) {
-       changed = !CFEqual(prev_ipv4_primary, primary_ipv4);
-    }
-    else {
-       changed = TRUE;
-    }
-    if (primary_ipv4 != NULL) {
-       CFRetain(primary_ipv4);
-    }
-    if (prev_ipv4_primary != NULL) {
-       CFRelease(prev_ipv4_primary);
-    }
-    watcher->primary_ipv4 = primary_ipv4;
-    if (changed) {
-       if (primary_ipv4 != NULL) {
-           SCLog(S_NetworkIdentification_debug,
-                 LOG_NOTICE, CFSTR("Primary IPv4 %@"), primary_ipv4);
-       }
-       else {
-           SCLog(S_NetworkIdentification_debug, LOG_NOTICE,
-                 CFSTR("No Primary IPv4"));
-       }
-    }
- done:
-    return (changed);
-}
-
-
-static CFDictionaryRef
-signature_add_service(CFDictionaryRef sig_dict, CFDictionaryRef service,
-                     CFArrayRef active_services)
-{
-    CFArrayRef                 list;
-    CFMutableDictionaryRef     new_dict = NULL;
-    CFDateRef                  now;
-
-    list = CFDictionaryGetValue(sig_dict, kServices);
-    now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
-    if (list == NULL) {
-       list = CFArrayCreate(NULL, (const void * *)&service, 1,
-                            &kCFTypeArrayCallBacks);
-    }
-    else {
-       int                     list_count = CFArrayGetCount(list);
-       CFMutableArrayRef       new_list = NULL;
-       CFRange                 range = CFRangeMake(0, list_count);
-       int                     where;
-
-       where = CFArrayGetFirstIndexOfValue(list, range, service);
-       if (where != kCFNotFound) {
-           CFDateRef           date;
-
-           date = CFDictionaryGetValue(sig_dict, kTimestamp);
-           if (date != NULL) {
-               CFTimeInterval  time_interval;
-               
-               time_interval = CFDateGetTimeIntervalSinceDate(now, date);
-               /* don't bother updating timestamp until interval has passed */
-               if (time_interval < (SIGNATURE_UPDATE_INTERVAL_SECS)) {
-                   goto done;
-               }
-           }
-           if (where == 0) {
-               /* it's already in the right place */
-               list = NULL;
-           }
-       }
-
-       if (list != NULL) {
-           new_list = CFArrayCreateMutableCopy(NULL, 0, list);
-           if (where != kCFNotFound) {
-               CFArrayRemoveValueAtIndex(new_list, where);
-           }
-           else {
-               list_count++;
-           }
-           CFArrayInsertValueAtIndex(new_list, 0, service);
-           /* try to remove stale entries */
-           if (list_count > SERVICE_HISTORY_MAX) {
-               int i;
-               int remove_count = list_count - SERVICE_HISTORY_MAX;
-
-               SCLog(S_NetworkIdentification_debug,
-                     LOG_NOTICE, CFSTR("Attempting to remove %d services"),
-                     remove_count);
-               for (i = list_count - 1; i >= 0 && remove_count > 0; i--) {
-                   CFDictionaryRef     dict;
-           
-                   dict = CFArrayGetValueAtIndex(new_list, i);
-                   if (myCFDictionaryArrayGetValue(active_services,
-                                                   kService, dict, NULL)
-                       != NULL) {
-                       /* skip anything that's currently active */
-                       SCLog(S_NetworkIdentification_debug,
-                             LOG_NOTICE, CFSTR("Skipping Service %@"),
-                             dict);
-                   }
-                   else {
-                       SCLog(S_NetworkIdentification_debug, LOG_NOTICE,
-                             CFSTR("Removing Service %@"), dict);
-                       CFArrayRemoveValueAtIndex(new_list, i);
-                       remove_count--;
-                   }
-               }
-           }
-           list = (CFArrayRef)new_list;
-           
-       }
-    }
-
-    new_dict = CFDictionaryCreateMutableCopy(NULL, 0, sig_dict);
-    if (list != NULL) {
-       CFDictionarySetValue(new_dict, kServices, list);
-       CFRelease(list);
-    }
-    CFDictionarySetValue(new_dict, kTimestamp, now);
-
- done:
-    CFRelease(now);
-    return (new_dict);
-}
-
-#define ARBITRARILY_LARGE_NUMBER       (1024 * 1024)
-static CFStringRef
-get_best_serviceID(CFArrayRef serviceID_list, CFArrayRef order)
-{
-    int                        best_rank;
-    CFStringRef                best_serviceID;
-    int                        count;
-    int                        i;
-    CFRange            range;
-
-    count = CFArrayGetCount(serviceID_list);
-    if (count == 1 || order == NULL) {
-       return (CFArrayGetValueAtIndex(serviceID_list, 0));
-    }
-    best_serviceID = NULL;
-    best_rank = ARBITRARILY_LARGE_NUMBER;
-    range = CFRangeMake(0, CFArrayGetCount(order));
-    for (i = 0; i < count; i++) {
-       CFStringRef     serviceID = CFArrayGetValueAtIndex(serviceID_list, i);
-       int             this_rank;
-
-       this_rank = CFArrayGetFirstIndexOfValue(order, range, serviceID);
-       if (this_rank == kCFNotFound) {
-           this_rank = ARBITRARILY_LARGE_NUMBER;
-       }
-       if (best_serviceID == NULL || this_rank < best_rank) {
-           best_serviceID = serviceID;
-           best_rank = this_rank;
-       }
-    }
-    return (best_serviceID);
-}
-
-static CFArrayRef
-copy_service_order(SCDynamicStoreRef session, CFStringRef ipv4_key)
-{
-    CFArrayRef                 order = NULL;
-    CFDictionaryRef            ipv4_dict = NULL;
-
-    if (session == NULL) {
-       return (NULL);
-    }
-    ipv4_dict = SCDynamicStoreCopyValue(session, ipv4_key);
-    if (isA_CFDictionary(ipv4_dict) != NULL) {
-       order = CFDictionaryGetValue(ipv4_dict, kSCPropNetServiceOrder);
-       order = isA_CFArray(order);
-       if (order) {
-           CFRetain(order);
-       }
-    }
-    if (ipv4_dict != NULL) {
-       CFRelease(ipv4_dict);
-    }
-    return (order);
-}
-
-typedef struct service_order_with_range {
-    CFArrayRef service_order;
-    CFRange    range;
-} service_order_with_range_t;
-
-static void
-add_netID_and_serviceID(service_order_with_range_t * order, int count,
-                       CFMutableArrayRef netID_list, CFStringRef netID,
-                       CFMutableArrayRef serviceID_list, CFStringRef serviceID)
-        
-{
-    int                i;
-    int                serviceID_index;
-
-    if (count == 0 || order->service_order == NULL) {
-       goto add_to_end;
-    }
-    serviceID_index = CFArrayGetFirstIndexOfValue(order->service_order,
-                                                 order->range,
-                                                 serviceID);
-    if (serviceID_index == kCFNotFound) {
-       goto add_to_end;
-    }
-    for (i = 0; i < count; i++) {
-       CFStringRef     scan = CFArrayGetValueAtIndex(serviceID_list, i);
-       int             scan_index;
-       
-       scan_index = CFArrayGetFirstIndexOfValue(order->service_order,
-                                                order->range,
-                                                scan);
-       if (scan_index == kCFNotFound
-           || serviceID_index < scan_index) {
-           /* found our insertion point */
-           CFArrayInsertValueAtIndex(netID_list, i, netID);
-           CFArrayInsertValueAtIndex(serviceID_list, i, serviceID);
-           return;
-       }
-    }
-
- add_to_end:
-    CFArrayAppendValue(netID_list, netID);
-    CFArrayAppendValue(serviceID_list, serviceID);
-    return;
-}
-
-static Boolean
-ServiceWatcherPublishActiveIdentifiers(ServiceWatcherRef watcher)
-{
-    Boolean    updated = FALSE;
-
-    if (watcher->active_signatures == NULL) {
-       CFDictionaryRef dict;
-
-       dict = SCDynamicStoreCopyValue(watcher->store,
-                                      kSCNetworkIdentificationStoreKey);
-       if (dict != NULL) {
-           updated = TRUE;
-           SCLog(S_NetworkIdentification_debug,
-                 LOG_NOTICE, CFSTR("Removing %@"),
-                 kSCNetworkIdentificationStoreKey);
-           SCDynamicStoreRemoveValue(watcher->store,
-                                     kSCNetworkIdentificationStoreKey);
-           CFRelease(dict);
-       }
-    }
-    else {
-       int                     count;
-       CFDictionaryRef         dict;
-       int                     i;
-       CFMutableArrayRef       id_list;
-       CFStringRef             keys[3];
-       int                     keys_count;
-       service_order_with_range_t order;
-       CFStringRef             primary_ipv4_id = NULL;
-       CFMutableArrayRef       serviceID_list;
-       CFDictionaryRef         store_dict;
-       CFTypeRef               values[3];
-
-       order.service_order = copy_service_order(watcher->store,
-                                                watcher->setup_ipv4_key);
-       if (order.service_order != NULL) {
-           order.range = CFRangeMake(0, CFArrayGetCount(order.service_order));
-       }
-       id_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       serviceID_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       count = CFArrayGetCount(watcher->active_signatures);
-       for (i = 0; i < count; i++) {
-           CFStringRef                 this_id;
-           CFStringRef                 serviceID;
-           CFArrayRef                  this_list;
-
-           dict = CFArrayGetValueAtIndex(watcher->active_signatures, i);
-           this_id = CFDictionaryGetValue(dict, kIdentifier);
-           this_list = CFDictionaryGetValue(dict, kServiceIdentifiers);
-           if (primary_ipv4_id == NULL && watcher->primary_ipv4 != NULL) {
-               CFRange                 range;
-
-               range = CFRangeMake(0, CFArrayGetCount(this_list));
-               if (CFArrayContainsValue(this_list, range, 
-                                        watcher->primary_ipv4)) {
-                   primary_ipv4_id = this_id;
-               }
-           }
-           serviceID = get_best_serviceID(this_list, order.service_order);
-           add_netID_and_serviceID(&order, i, id_list, this_id,
-                                   serviceID_list, serviceID);
-       }
-       keys[0] = kStoreKeyActiveIdentifiers;
-       values[0] = id_list;
-       keys[1] = kStoreKeyServiceIdentifiers;
-       values[1] = serviceID_list;
-       if (primary_ipv4_id != NULL) {
-           keys_count = 3;
-           keys[2] = kStoreKeyPrimaryIPv4Identifier;
-           values[2] = primary_ipv4_id;
-       }
-       else {
-           keys_count = 2;
-       }
-       dict = CFDictionaryCreate(NULL, (const void * *)keys,
-                                 (const void * *)values, keys_count,
-                                 &kCFTypeDictionaryKeyCallBacks,
-                                 &kCFTypeDictionaryValueCallBacks);
-       store_dict
-           = SCDynamicStoreCopyValue(watcher->store,
-                                     kSCNetworkIdentificationStoreKey);
-       if (isA_CFDictionary(store_dict) == NULL
-           || CFEqual(store_dict, dict) == FALSE) {
-           updated = TRUE;
-           SCDynamicStoreSetValue(watcher->store,
-                                  kSCNetworkIdentificationStoreKey, dict);
-           SCLog(S_NetworkIdentification_debug,
-                 LOG_NOTICE, CFSTR("Setting %@ = %@"),
-                 kSCNetworkIdentificationStoreKey,
-                 dict);
-       }
-       else {
-           SCLog(S_NetworkIdentification_debug,
-                 LOG_NOTICE, CFSTR("Not setting %@"),
-                 kSCNetworkIdentificationStoreKey);
-       }
-       CFRelease(dict);
-       CFRelease(id_list);
-       CFRelease(serviceID_list);
-       if (order.service_order != NULL) {
-           CFRelease(order.service_order);
-       }
-       if (store_dict != NULL) {
-           CFRelease(store_dict);
-       }
-    }
-    return (updated);
-}
-
-static CFDictionaryRef
-signature_dict_create(CFStringRef this_sig, CFDictionaryRef service)
-{
-    CFDictionaryRef            dict;
-    const void *               keys[4];
-    const void *               values[4];
-
-    keys[0] = kSignature;
-    values[0] = this_sig;
-
-    keys[1] = kServices;
-    values[1] = CFArrayCreate(NULL, (const void * *)&service, 1,
-                             &kCFTypeArrayCallBacks);
-    keys[2] = kIdentifier;
-    values[2] = this_sig;
-
-    keys[3] = kTimestamp;
-    values[3] = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
-
-    dict = CFDictionaryCreate(NULL, keys, values,
-                             sizeof(keys) / sizeof(keys[0]),
-                             &kCFTypeDictionaryKeyCallBacks,
-                             &kCFTypeDictionaryValueCallBacks);
-    CFRelease(values[1]);
-    CFRelease(values[3]);
-    return (dict);
-}
-
-static void
-ServiceWatcherRemoveStaleSignatures(ServiceWatcherRef watcher)
-{
-    int                        active_count = 0;
-    int                        count;
-    int                        i;
-    int                        remove_count;
-
-    count = CFArrayGetCount(watcher->signatures);
-    if (watcher->active_signatures != NULL) {
-       active_count = CFArrayGetCount(watcher->active_signatures);
-    }
-    if ((count - active_count) <= SIGNATURE_HISTORY_MAX) {
-       return;
-    }
-    remove_count = count - active_count - SIGNATURE_HISTORY_MAX;
-    for (i = count - 1; i >= 0 && remove_count > 0; i--) {
-       CFDictionaryRef         sig_dict;
-       CFStringRef             sig_str;
-       
-       sig_dict = CFArrayGetValueAtIndex(watcher->signatures, i);
-       sig_str = CFDictionaryGetValue(sig_dict, kSignature);
-       
-       if (myCFDictionaryArrayGetValue(watcher->active_signatures, 
-                                       kSignature, sig_str, NULL)
-           != NULL) {
-           /* skip anything that's currently active */
-           SCLog(S_NetworkIdentification_debug,
-                 LOG_NOTICE, CFSTR("Skipping %@"), sig_dict);
-       }
-       else {
-           SCLog(S_NetworkIdentification_debug,
-                 LOG_NOTICE, CFSTR("ServiceWatcher: Removing %@"),
-                 sig_dict);
-           CFArrayRemoveValueAtIndex(watcher->signatures, i);
-           remove_count--;
-       }
-    }
-    return;
-}
-
-static void
-ServiceWatcherSaveSignatures(ServiceWatcherRef watcher)
-{
-    SCPreferencesRef   prefs;
-
-    prefs = SCPreferencesCreate(NULL, CFSTR("ServiceWatcher"),
-                               kSCNetworkIdentificationPrefsKey);
-    if (prefs == NULL) {
-       SCLog(TRUE, LOG_NOTICE, CFSTR("ServiceWatcherSaveSignatures: Create failed %s"),
-             SCErrorString(SCError()));
-       return;
-    }
-    ServiceWatcherRemoveStaleSignatures(watcher);
-    if (SCPreferencesSetValue(prefs, kSignatures, watcher->signatures)
-       == FALSE) {
-       SCLog(TRUE, LOG_NOTICE, CFSTR("ServiceWatcherSaveSignatures: Set failed %s"),
-             SCErrorString(SCError()));
-    }
-    else if (SCPreferencesCommitChanges(prefs) == FALSE) {
-       // An EROFS error is expected during installation.  All other
-       // errors should be reported.
-       if (SCError() != EROFS) {
-           SCLog(TRUE, LOG_NOTICE, CFSTR("ServiceWatcherSaveSignatures: Commit failed %s"),
-                 SCErrorString(SCError()));
-       }
-    }
-    CFRelease(prefs);
-    return;
-
-}
-
-static void
-ServiceWatcherLoadSignatures(ServiceWatcherRef watcher)
-{
-    int                        count;
-    int                        i;
-    SCPreferencesRef   prefs;
-    CFArrayRef         signatures;
-
-    watcher->signatures 
-       = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    prefs = SCPreferencesCreate(NULL, CFSTR("ServiceWatcher"),
-                               kSCNetworkIdentificationPrefsKey);
-    if (prefs == NULL) {
-       SCLog(TRUE, LOG_NOTICE, CFSTR("ServiceWatcherLoadSignatures: Create failed %s"),
-             SCErrorString(SCError()));
-       return;
-    }
-    signatures = SCPreferencesGetValue(prefs, kSignatures);
-    if (signatures == NULL) {
-       goto done;
-    }
-    if (isA_CFArray(signatures) == NULL) {
-       SCLog(TRUE, LOG_NOTICE,
-             CFSTR("ServiceWatcherLoadSignatures: Signatures is not an array"));
-       goto done;
-    }
-    count = CFArrayGetCount(signatures);
-    for (i = 0; i < count; i++) {
-       CFDictionaryRef         dict;
-       CFArrayRef              services;
-       CFStringRef             sig_id;
-       CFStringRef             sig_str;
-       CFDateRef               timestamp;
-
-       dict = CFArrayGetValueAtIndex(signatures, i);
-       if (isA_CFDictionary(dict) == NULL) {
-           continue;
-       }
-       sig_id = CFDictionaryGetValue(dict, kIdentifier);
-       if (isA_CFString(sig_id) == NULL) {
-           continue;
-       }
-       sig_str = CFDictionaryGetValue(dict, kSignature);
-       if (isA_CFString(sig_str) == NULL) {
-           continue;
-       }
-       timestamp = CFDictionaryGetValue(dict, kTimestamp);
-       if (isA_CFDate(timestamp) == NULL) {
-           continue;
-       }
-       services = CFDictionaryGetValue(dict, kServices);
-       if (isA_CFArray(services) == NULL) {
-           continue;
-       }
-       CFArrayAppendValue(watcher->signatures, dict);
-    }
-
- done:
-    CFRelease(prefs);
-    return;
-
-}
-
-static void
-ServiceWatcherUpdate(ServiceWatcherRef watcher, Boolean update_signatures)
-{
-    CFMutableArrayRef  active_signatures = NULL;
-    int                        count;
-    int                        i;
-    Boolean            save_signatures = FALSE;
-    CFArrayRef         service_list;
-    Boolean            update_store = FALSE;
-
-    service_list = ServiceWatcherCopyCurrent(watcher);
-    SCLog(S_NetworkIdentification_debug,
-         LOG_NOTICE, CFSTR("service_list = %@"), service_list);
-    if (service_list == NULL) {
-       goto done;
-    }
-    active_signatures = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    count = CFArrayGetCount(service_list);
-    for (i = 0; i < count; i++) {
-       CFDictionaryRef         dict;
-       CFDictionaryRef         active_dict;
-       CFArrayRef              id_list;
-       CFMutableDictionaryRef  new_active_dict;
-       CFDictionaryRef         new_sig_dict;
-       CFStringRef             serviceID;
-       CFStringRef             sig_id;
-       CFDictionaryRef         service;
-       CFDictionaryRef         sig_dict;
-       CFStringRef             this_sig;
-       int                     where;
-
-       dict = CFArrayGetValueAtIndex(service_list, i);
-       service = CFDictionaryGetValue(dict, kService);
-       this_sig = CFDictionaryGetValue(dict, kSignature);
-       if (this_sig == NULL) {
-           /* service has no signature */
-           continue;
-       }
-       sig_dict =  myCFDictionaryArrayGetValue(watcher->signatures, kSignature,
-                                               this_sig, &where);
-       if (sig_dict == NULL) {
-           /* add a new signature entry */
-           sig_dict = signature_dict_create(this_sig, service);
-           CFArrayInsertValueAtIndex(watcher->signatures, 0, sig_dict);
-           CFRelease(sig_dict);
-           save_signatures = TRUE;
-           sig_id = CFDictionaryGetValue(sig_dict, kIdentifier);
-           active_dict = NULL;
-       }
-       else {
-           /* update an existing signature entry */
-           
-           sig_id = CFDictionaryGetValue(sig_dict, kIdentifier);
-           new_sig_dict = signature_add_service(sig_dict, service,
-                                                service_list);
-           if (new_sig_dict != NULL) {
-               CFArrayRemoveValueAtIndex(watcher->signatures, where);
-               CFArrayInsertValueAtIndex(watcher->signatures, 0,
-                                         new_sig_dict);
-               CFRelease(new_sig_dict);
-               save_signatures = TRUE;
-           }
-           active_dict
-               = myCFDictionaryArrayGetValue(active_signatures, 
-                                             kSignature, this_sig,
-                                             &where);
-       }
-       if (active_dict == NULL) {
-           /* signature now active, this is the first/only service */
-           new_active_dict 
-               = CFDictionaryCreateMutable(NULL, 0,
-                                           &kCFTypeDictionaryKeyCallBacks,
-                                           &kCFTypeDictionaryValueCallBacks);
-           CFDictionarySetValue(new_active_dict, kSignature, this_sig);
-           CFDictionarySetValue(new_active_dict, kIdentifier, sig_id);
-           serviceID = CFDictionaryGetValue(service, kServiceID);
-           id_list = CFArrayCreate(NULL, (const void * *)&serviceID, 1,
-                                   &kCFTypeArrayCallBacks);
-           CFDictionarySetValue(new_active_dict, kServiceIdentifiers,
-                                id_list);
-           CFArrayAppendValue(active_signatures, new_active_dict);
-           CFRelease(new_active_dict);
-           CFRelease(id_list);
-       }
-       else {
-           /* signature already active, add this serviceID */
-           CFRange                     range;
-           
-           id_list = CFDictionaryGetValue(active_dict,
-                                          kServiceIdentifiers);
-           range = CFRangeMake(0, CFArrayGetCount(id_list));
-           serviceID = CFDictionaryGetValue(service, kServiceID);
-           if (CFArrayContainsValue(id_list, range, serviceID) == FALSE) {
-               CFMutableDictionaryRef  new_active_dict;
-               CFMutableArrayRef       new_id_list;
-               
-               new_id_list = CFArrayCreateMutableCopy(NULL, 0, id_list);
-               CFArrayAppendValue(new_id_list, serviceID);
-               new_active_dict 
-                   = CFDictionaryCreateMutableCopy(NULL, 0, active_dict);
-               CFDictionarySetValue(new_active_dict, kServiceIdentifiers,
-                                    new_id_list);
-               CFArraySetValueAtIndex(active_signatures, where,
-                                      new_active_dict);
-               CFRelease(new_active_dict);
-               CFRelease(new_id_list);
-           }
-       }
-    }
- done:
-    if (active_signatures == NULL
-       || CFArrayGetCount(active_signatures) == 0) {
-       update_store
-           = ServiceWatcherSetActiveSignatures(watcher, NULL);
-    }
-    else {
-       update_store
-           = ServiceWatcherSetActiveSignatures(watcher, active_signatures);
-    }
-    if (save_signatures) {
-       /* write out the file */
-       ServiceWatcherSaveSignatures(watcher);
-    }
-
-    if (service_list != NULL) {
-       CFRelease(service_list);
-    }
-    if (active_signatures != NULL) {
-       CFRelease(active_signatures);
-    }
-    if (update_signatures || update_store) {
-       if (ServiceWatcherPublishActiveIdentifiers(watcher)) {
-           notify_post(kSCNetworkSignatureActiveChangedNotifyName);
-       }
-    }
-    return;
-}
-
-static Boolean
-update_primary_ipv4(ServiceWatcherRef watcher)
-{
-    Boolean            changed = FALSE;
-    CFDictionaryRef    global_ipv4;
-    
-    global_ipv4 = SCDynamicStoreCopyValue(watcher->store,
-                                         watcher->state_ipv4_key);
-    if (isA_CFDictionary(global_ipv4) != NULL) {
-       CFStringRef             primary_ipv4;
-
-       primary_ipv4 
-           = CFDictionaryGetValue(global_ipv4,
-                                  kSCDynamicStorePropNetPrimaryService);
-       changed = ServiceWatcherSetPrimaryIPv4(watcher,
-                                              isA_CFString(primary_ipv4));
-    }
-    if (global_ipv4 != NULL) {
-       CFRelease(global_ipv4);
-    }
-    return (changed);
-}
-
-static void
-ServiceWatcherNotifier(SCDynamicStoreRef not_used, CFArrayRef changes,
-                      void * info)
-{
-    int                        count;
-    int                        i;
-    Boolean            order_changed = FALSE;
-    Boolean            global_ipv4_changed = FALSE;
-    Boolean            primary_ipv4_changed = FALSE;
-    ServiceWatcherRef  watcher = (ServiceWatcherRef)info;
-
-    count = CFArrayGetCount(changes);
-    if (count == 0) {
-       return;
-    }
-    for (i = 0; i < count; i++) {
-       CFStringRef     key = CFArrayGetValueAtIndex(changes, i);
-
-       if (CFStringHasPrefix(key, kSCDynamicStoreDomainSetup)) {
-           order_changed = TRUE;
-       }
-       else if (CFEqual(key, watcher->state_ipv4_key)) {
-           global_ipv4_changed = TRUE;
-       }
-    }
-    if (global_ipv4_changed) {
-       primary_ipv4_changed = update_primary_ipv4(watcher);
-    }
-    if (count == 1
-       && (order_changed || primary_ipv4_changed)) {
-       /* just the service order or the primary service changed */
-       if (ServiceWatcherPublishActiveIdentifiers(watcher)) {
-           notify_post(kSCNetworkSignatureActiveChangedNotifyName);
-       }
-    }
-    else {
-       ServiceWatcherUpdate(watcher, order_changed || primary_ipv4_changed);
-    }
-    return;
-}
-
-static ServiceWatcherRef
-ServiceWatcherCreate()
-{
-    SCDynamicStoreContext      context = { 0, 0, 0, 0, 0};
-    CFArrayRef                 patterns;
-    CFStringRef                        keys[2];
-    CFArrayRef                 key_list;
-    ServiceWatcherRef          watcher;
-
-    watcher = malloc(sizeof(*watcher));
-    bzero(watcher, sizeof(*watcher));
-    context.info = watcher;
-    watcher->store = SCDynamicStoreCreate(NULL, CFSTR("Service Watcher"),
-                                         ServiceWatcherNotifier, &context);
-    if (watcher->store == NULL) {
-       SCLog(TRUE, LOG_NOTICE, CFSTR("SCDynamicStoreCreate failed: %s"),
-             SCErrorString(SCError()));
-       goto failed;
-    }
-    watcher->setup_ipv4_key 
-       = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 
-                                                    kSCDynamicStoreDomainSetup,
-                                                    kSCEntNetIPv4);
-    watcher->state_ipv4_key 
-       = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 
-                                                    kSCDynamicStoreDomainState,
-                                                    kSCEntNetIPv4);
-    keys[0] = watcher->setup_ipv4_key;
-    keys[1] = watcher->state_ipv4_key;
-    key_list = CFArrayCreate(NULL, (const void * *)keys, sizeof(keys) / sizeof(keys[0]),
-                            &kCFTypeArrayCallBacks);
-    patterns = ServiceWatcherNotificationPatterns();
-    (void)SCDynamicStoreSetNotificationKeys(watcher->store, key_list, patterns);
-    CFRelease(patterns);
-    CFRelease(key_list);
-    watcher->rls = SCDynamicStoreCreateRunLoopSource(NULL, watcher->store, 0);
-    CFRunLoopAddSource(CFRunLoopGetCurrent(), watcher->rls, 
-                      kCFRunLoopDefaultMode);
-    ServiceWatcherLoadSignatures(watcher);
-    update_primary_ipv4(watcher);
-    return (watcher);
- failed:
-    ServiceWatcherFree(&watcher);
-    return (NULL);
-}
-
-void
-ServiceWatcherFree(ServiceWatcherRef * watcher_p)
-{
-    ServiceWatcherRef  watcher;
-
-    if (watcher_p == NULL) {
-       return;
-    }
-    watcher = *watcher_p;
-    if (watcher == NULL) {
-       return;
-    }
-    *watcher_p = NULL;
-    if (watcher->store != NULL) {
-       CFRelease(watcher->store);
-       watcher->store = NULL;
-    }
-    if (watcher->rls != NULL) {
-       CFRunLoopSourceInvalidate(watcher->rls);
-       CFRelease(watcher->rls);
-       watcher->rls = NULL;
-    }
-    if (watcher->signatures != NULL) {
-       CFRelease(watcher->signatures);
-       watcher->signatures = NULL;
-    }
-    if (watcher->state_ipv4_key != NULL) {
-       CFRelease(watcher->state_ipv4_key);
-       watcher->state_ipv4_key = NULL;
-    }
-    if (watcher->setup_ipv4_key != NULL) {
-       CFRelease(watcher->setup_ipv4_key);
-       watcher->setup_ipv4_key = NULL;
-    }
-    free(watcher);
-    return;
-}
-
-/* global service watcher instance */
-static ServiceWatcherRef       S_watcher;
-
-__private_extern__
-void
-prime_NetworkIdentification()
-{
-    if (S_NetworkIdentification_disabled) {
-       return;
-    }
-    S_watcher = ServiceWatcherCreate();
-    ServiceWatcherUpdate(S_watcher, TRUE);
-}
-
-__private_extern__
-void
-load_NetworkIdentification(CFBundleRef bundle, Boolean bundleVerbose)
-{
-    if (bundleVerbose) {
-       S_NetworkIdentification_debug = 1;
-    }
-    return;
-}
-
-#ifdef  TEST_NETWORKIDENTIFICATION
-#undef  TEST_NETWORKIDENTIFICATION
-
-int
-main(int argc, char **argv)
-{
-    _sc_log     = FALSE;
-    _sc_verbose = (argc > 1) ? TRUE : FALSE;
-
-    load_NetworkIdentification(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
-    prime_NetworkIdentification();
-    CFRunLoopRun();
-    /* not reached */
-    exit(0);
-    return 0;
-}
-#endif
-
index bc7fbcb6c40d2052e5471cf831e6af2cb8e148d1..8cf44b4fbea44b006dd451391e0fabaebc3ff823 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>Builtin</key>
        <true/>
        <key>Requires</key>
index bd496eb6c8dbde33dd44a86ca35df2d53155f7ee..0200299eb35e2024525e36343d96a3ed317de29d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008, 2010, 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -72,6 +72,7 @@ establishNewPreferences()
 {
        CFBundleRef     bundle;
        SCNetworkSetRef current         = NULL;
+       CFStringRef     new_model;
        Boolean         ok              = FALSE;
        int             sc_status       = kSCStatusFailed;
        SCNetworkSetRef set             = NULL;
@@ -95,6 +96,59 @@ establishNewPreferences()
                }
        }
 
+       /* Ensure that the preferences has the new model */
+       new_model = _SC_hw_model();
+
+       /* Need to regenerate the new configuration for new model */
+       if (new_model != NULL) {
+               CFStringRef     old_model;
+
+               old_model = SCPreferencesGetValue(prefs, MODEL);
+               if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
+                       CFIndex         count;
+                       CFIndex         index;
+                       CFArrayRef      keys;
+
+                       keys = SCPreferencesCopyKeyList(prefs);
+                       count = (keys != NULL) ? CFArrayGetCount(keys) : 0;
+                       // if new hardware
+                       for (index = 0; index < count; index++) {
+                               CFStringRef             existing_key;
+
+                               existing_key = CFArrayGetValueAtIndex(keys, index);
+
+                               if (isA_CFString(existing_key) != NULL) {
+                                       CFStringRef             new_key;
+                                       CFPropertyListRef       value;
+
+                                       /* If it already contains a Model
+                                          or if it already contains a MODEL:KEY key skip it*/
+                                       if (CFEqual(existing_key, MODEL)
+                                           || CFStringFind(existing_key, CFSTR(":"), 0).location
+                                           != kCFNotFound) {
+                                               continue;
+                                       }
+
+                                       value = SCPreferencesGetValue(prefs, existing_key);
+
+                                       /* Create a new key as OLD_MODEL:OLD_KEY */
+                                       new_key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"),
+                                                                          old_model, existing_key);
+                                       SCPreferencesSetValue(prefs, new_key, value);
+                                       SCPreferencesRemoveValue(prefs, existing_key);
+                                       CFRelease(new_key);
+                               }
+                       }
+
+                       if (keys != NULL) {
+                               CFRelease(keys);
+                       }
+               }
+
+               /* Set the new model */
+               SCPreferencesSetValue(prefs, MODEL, new_model);
+       }
+
        current = SCNetworkSetCopyCurrent(prefs);
        if (current != NULL) {
                set = current;
@@ -569,11 +623,18 @@ updateSCDynamicStore(SCPreferencesRef prefs)
        }
 
        /* Update the dynamic store */
+#ifndef MAIN
        if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) {
                SCLog(TRUE, LOG_ERR,
                      CFSTR("SCDynamicStoreSetMultiple() failed: %s"),
                      SCErrorString(SCError()));
        }
+#else  // !MAIN
+       SCLog(TRUE, LOG_NOTICE,
+             CFSTR("SCDynamicStore\nset: %@\nremove: %@\n"),
+             newPrefs,
+             removedPrefsKeys);
+#endif // !MAIN
 
        CFRelease(currentPrefs);
        CFRelease(newPrefs);
@@ -663,15 +724,37 @@ load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
        }
 
        /* open a SCPreferences session */
+#ifndef        MAIN
        prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
+#else  // !MAIN
+       prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
+#endif // !MAIN
        if (prefs != NULL) {
-               SCNetworkSetRef current;
+               Boolean         need_update = FALSE;
+               CFStringRef     new_model;
 
-               current = SCNetworkSetCopyCurrent(prefs);
-               if (current != NULL) {
-                       /* network configuration available, disable template creation */
-                       initPrefs = FALSE;
-                       CFRelease(current);
+               new_model = _SC_hw_model();
+
+               /* Need to regenerate the new configuration for new model */
+               if (new_model != NULL) {
+                       CFStringRef     old_model;
+
+                       old_model = SCPreferencesGetValue(prefs, MODEL);
+                       if (old_model != NULL && !_SC_CFEqual(old_model, new_model)) {
+                               // if new hardware
+                               need_update = TRUE;
+                       }
+               }
+
+               if (need_update == FALSE) {
+                       SCNetworkSetRef current;
+
+                       current = SCNetworkSetCopyCurrent(prefs);
+                       if (current != NULL) {
+                               /* network configuration available, disable template creation */
+                               initPrefs = FALSE;
+                               CFRelease(current);
+                       }
                }
        } else {
                SCLog(TRUE, LOG_ERR,
diff --git a/Plugins/SCNetworkReachability/Info.plist b/Plugins/SCNetworkReachability/Info.plist
new file mode 100644 (file)
index 0000000..172cd34
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Builtin</key>
+       <true/>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>SCNetworkReachability</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.apple.SystemConfiguration.SCNetworkReachability</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>com.apple.SystemConfiguration.SCNetworkReachability</string>
+       <key>CFBundlePackageType</key>
+       <string>BNDL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.12</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.12</string>
+</dict>
+</plist>
diff --git a/Plugins/SCNetworkReachability/Makefile b/Plugins/SCNetworkReachability/Makefile
new file mode 100644 (file)
index 0000000..d1576e4
--- /dev/null
@@ -0,0 +1,56 @@
+ARCHS  = -arch i386 -arch x86_64
+CFLAGS = -Wall -pipe -O0 -gdwarf-2
+
+REACH_SERVER_C = ../../SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_server.c
+
+REACH_SERVER_PLIST = /Library/LaunchDaemons/com.apple.SCNetworkReachability.plist
+SYMROOT            = ${shell basename ${shell dirname ${shell dirname ${PWD}}}}
+
+all: /var/tmp/reach_server ${REACH_SERVER_PLIST}
+
+${REACH_SERVER_PLIST}: Makefile
+       @sudo mkdir -p ${shell dirname ${REACH_SERVER_PLIST}}
+       @sudo launchctl unload -w ${REACH_SERVER_PLIST}                         > /dev/null 2>&1 || /usr/bin/true
+       @sudo rm -f ${REACH_SERVER_PLIST}
+       @sudo defaults write ${REACH_SERVER_PLIST} Label                        \
+                       SCNetworkReachability-DEBUG
+       @sudo defaults write ${REACH_SERVER_PLIST} MachServices                 \
+               -dict                                                           \
+                       SCNetworkReachability-DEBUG                             \
+                               -bool TRUE
+       @sudo defaults write ${REACH_SERVER_PLIST} Program                      \
+                       /var/tmp/reach_server
+       @sudo defaults write ${REACH_SERVER_PLIST} ProgramArguments             \
+               -array                                                          \
+                       SCNetworkReachability-DEBUG                             \
+                       verbose
+       @sudo defaults write ${REACH_SERVER_PLIST} EnvironmentVariables         \
+               -dict                                                           \
+                       DYLD_FRAMEWORK_PATH                                     \
+                               ${BUILDIT_DIR}/${SYMROOT}.roots/${SYMROOT}~sym  \
+                       REACH_SERVER                                            \
+                               SCNetworkReachability-DEBUG
+       @sudo defaults write ${REACH_SERVER_PLIST} ThrottleInterval             \
+                       -int 5
+       @sudo chown root:wheel ${REACH_SERVER_PLIST}
+       @sudo chmod 644 ${REACH_SERVER_PLIST}
+       sudo launchctl load -w ${REACH_SERVER_PLIST}
+
+reach_server.o: ${REACH_SERVER_C}
+       cc ${ARCHS} ${CFLAGS} -DMAIN -I ../../SystemConfiguration.fproj -F ${BUILDIT_DIR}/${SYMROOT}.roots/${SYMROOT}~sym -c -o reach_server.o ${REACH_SERVER_C}
+
+reach_server: reach_server.o
+       cc ${ARCHS} -o reach_server reach_server.o -framework CoreFoundation -F ${BUILDIT_DIR}/${SYMROOT}.roots/${SYMROOT}~sym -framework SystemConfiguration
+       dsymutil reach_server -o reach_server.dSYM
+
+/var/tmp/reach_server: reach_server
+       @sudo rm -f /var/tmp/reach_server
+       cp -p reach_server /var/tmp/reach_server
+       @sudo chown root:wheel /var/tmp/reach_server
+       @sudo chmod 755 /var/tmp/reach_server
+
+clean:
+       sudo launchctl unload -w ${REACH_SERVER_PLIST}                          > /dev/null 2>&1 || /usr/bin/true
+       @sudo rm -f ${REACH_SERVER_PLIST}
+       @sudo rm -rf /var/tmp/reach_server
+       rm -rf *.o reach_server reach_server.dSYM
index fbc326f4c96db81c631f0c2e0c9ab750b5eedbdc..fe4e0dee925452434415a6abc98e5ae4cc5905e6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003, 2004, 2006, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -81,6 +81,7 @@ cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
                                 CFRangeMake(0, CFArrayGetCount(cached_removals)),
                                 key)) {
                // if we have "removed" the key
+               _SCErrorSet(kSCStatusNoKey);
                return NULL;
        }
 
index 8789a633c5c3e78fdd3c863197b533e62f446eb4..153ad6ff45611817ab14f52cb707933396e42736 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>CFPlugInDynamicRegistration</key>
        <string>NO</string>
        <key>CFPlugInFactories</key>
index a7d3fefe101eed21187f4f6ea56157d1dd4770a8..ca340286e9556bb48d89906566fdcc15de42ed67 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *   "Configure"  Automatically configure this interface without any
  *                intervention.
  *
- *   Note: automatic configuration may require authorization if the logged
- *         in user is NOT "root" (eUID==0) or if the "system.preferences"
- *         administrator right is not currently available.
+ *   Note: automatic configuration may not be possible if the logged in user
+ *         is NOT "root" (eUID==0) or if the authorization right that governs
+ *         SCHelper write operations (kSCPreferencesWriteAuthorizationRight)
+ *         is not currently available.
  *
  * An [older] "User Intervention" key is also supported.  That CFBoolean
  * key, if present and TRUE, implies "Configure" configuration of the
@@ -144,7 +145,7 @@ hasAuthorization(MyType *myInstance)
                AuthorizationRights     rights;
                OSStatus                status;
 
-               items[0].name        = "system.preferences";
+               items[0].name        = kSCPreferencesWriteAuthorizationRight;
                items[0].value       = NULL;
                items[0].valueLength = 0;
                items[0].flags       = 0;
@@ -606,7 +607,8 @@ updateInterfaceList(MyType *myInstance)
                                        }
                                        CFArrayAppendValue(myInstance->interfaces_configure, interface);
                                } else if (hasAuthorization(myInstance)) {
-                                       // if we already have the "admin" (system.preferences) right, configure automatically (without user intervention)
+                                       // if we already have the "admin" (kSCPreferencesWriteAuthorizationRight)
+                                       // right, configure automatically (without user intervention)
                                        if (myInstance->interfaces_configure == NULL) {
                                                myInstance->interfaces_configure = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
                                        }
@@ -797,7 +799,8 @@ update_node(void *refCon, io_service_t service, natural_t messageType, void *mes
        MyType          *myInstance;
        MyNode          *myNode;
 
-       myNode     = (MyNode *)CFDataGetBytePtr(myData);
+       /* ALIGN: CF aligns to at least >8 bytes */
+       myNode     = (MyNode *)(void *)CFDataGetBytePtr(myData);
        myInstance = myNode->myInstance;
 
        switch (messageType) {
@@ -871,7 +874,10 @@ add_node_watcher(MyType *myInstance, io_registry_entry_t node, io_registry_entry
        // wait for initialization to complete
        myData = CFDataCreateMutable(NULL, sizeof(MyNode));
        CFDataSetLength(myData, sizeof(MyNode));
-       myNode = (MyNode *)CFDataGetBytePtr(myData);
+
+       /* ALIGN: CF aligns to at least >8 bytes */
+       myNode = (MyNode *)(void *)CFDataGetBytePtr(myData);
+
        bzero(myNode, sizeof(MyNode));
        if (interface != MACH_PORT_NULL) {
                IOObjectRetain(interface);
@@ -1034,7 +1040,10 @@ watcher_remove_serial(MyType *myInstance)
                        MyNode          *myNode;
 
                        myData = CFArrayGetValueAtIndex(myInstance->notifyNodes, i);
-                       myNode = (MyNode *)CFDataGetBytePtr(myData);
+
+                       /* ALIGN: CF aligns to at least >8 bytes */
+                       myNode = (MyNode *)(void *)CFDataGetBytePtr(myData);
+
                        if (myNode->interface != MACH_PORT_NULL) {
                                IOObjectRelease(myNode->interface);
                        }
index 806856c8733c151b57885147dc00852a0a6b62c4..3124eb15106f23d70b4602b26db8f47170d16d08 100644 (file)
@@ -279,12 +279,14 @@ SCBridgeInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs)
        available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        excluded  = CFSetCreateMutable  (NULL, 0, &kCFTypeSetCallBacks);
 
+#if    !TARGET_OS_IPHONE
        // exclude Bond [member] interfaces
        interfaces = SCBondInterfaceCopyAll(prefs);
        if (interfaces != NULL) {
                __SCBondInterfaceListCollectMembers(interfaces, excluded);
                CFRelease(interfaces);
        }
+#endif // !TARGET_OS_IPHONE
 
        // exclude Bridge [member] interfaces
        interfaces = SCBridgeInterfaceCopyAll(prefs);
index 413ebcebd5c68fd52f137f4f4a54243c2b722f3f..f295bb690b12001e492343ad9823cacea8e75cdc 100644 (file)
 #pragma mark -
 #pragma mark CaptiveNetwork.framework APIs (exported through the SystemConfiguration.framework)
 
+
+#if    TARGET_OS_EMBEDDED
 const CFStringRef kCNNetworkInfoKeySSIDData    = CFSTR("SSIDDATA");
 const CFStringRef kCNNetworkInfoKeySSID        = CFSTR("SSID");
 const CFStringRef kCNNetworkInfoKeyBSSID       = CFSTR("BSSID");
+#endif // TARGET_OS_EMBEDDED
+
 
 static void *
 __loadCaptiveNetwork(void) {
@@ -104,6 +108,8 @@ CNCopySupportedInterfaces(void)
        return dyfunc ? dyfunc() : NULL;
 }
 
+
+#if    TARGET_OS_EMBEDDED
 CFDictionaryRef
 CNCopyCurrentNetworkInfo(CFStringRef   interfaceName)
 {
@@ -114,3 +120,4 @@ CNCopyCurrentNetworkInfo(CFStringRef        interfaceName)
        }
        return dyfunc ? dyfunc(interfaceName) : NULL;
 }
+#endif // TARGET_OS_EMBEDDED
index 78d8fb9a45dcb4c028e48fbca4af9da515afe919..12fd409d2427482f4ce0e95d8303c276455ad421 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -56,15 +56,22 @@ __BEGIN_DECLS
        @function CNSetSupportedSSIDs
        @discussion Provides Captive Network Support with an updated list of
                SSIDs that this application will perform authentication on.
-               When Captive Network Support would show the Web Sheet for a
-               network with an SSID the application has registered for, it
-               will suppress showing the Web Sheet if the application is
-               still installed.
+
+               Captive Network Support suppresses showing the Web Sheet
+               for a captive Wi-Fi network if that network's SSID is in the
+               specified list.
+
+               On iOS, the registrations persist until the application is
+               removed from the device.
+
+               On MacOSX, the registrations persist as long as the application
+               is running.
+
        @param ssidArray A CFArray of CFStrings of the SSIDs.
        @result Returns TRUE if the operation succeeded, FALSE otherwise.
  */
 Boolean
-CNSetSupportedSSIDs    (CFArrayRef     ssidArray)              __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);
+CNSetSupportedSSIDs    (CFArrayRef     ssidArray)              __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_0);
 
 /*!
        @function CNMarkPortalOnline
@@ -76,7 +83,7 @@ CNSetSupportedSSIDs   (CFArrayRef     ssidArray)              __OSX_AVAILABLE_STARTING(__MAC_NA,__
        @result Returns TRUE if the operation succeeded, FALSE otherwise.
  */
 Boolean
-CNMarkPortalOnline     (CFStringRef    interfaceName)          __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);
+CNMarkPortalOnline     (CFStringRef    interfaceName)          __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_0);
 
 /*!
        @function CNMarkPortalOffline
@@ -86,7 +93,7 @@ CNMarkPortalOnline    (CFStringRef    interfaceName)          __OSX_AVAILABLE_STARTING(__MAC_N
        @result Returns TRUE if the operation succeeded, FALSE otherwise.
  */
 Boolean
-CNMarkPortalOffline    (CFStringRef    interfaceName)          __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);
+CNMarkPortalOffline    (CFStringRef    interfaceName)          __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_0);
 
 
 /*!
@@ -97,7 +104,9 @@ CNMarkPortalOffline  (CFStringRef    interfaceName)          __OSX_AVAILABLE_STARTING(__MAC_
         You MUST release the returned value.
  */
 CFArrayRef
-CNCopySupportedInterfaces      (void)                          __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_1);
+CNCopySupportedInterfaces      (void)                          __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_1);
+
+#if    TARGET_OS_EMBEDDED
 
 /*!
  @constant kCNNetworkInfoKeySSIDData
@@ -139,6 +148,8 @@ extern const CFStringRef kCNNetworkInfoKeyBSSID                     __OSX_AVAILABLE_STARTING(__MAC
 CFDictionaryRef
 CNCopyCurrentNetworkInfo       (CFStringRef interfaceName)     __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_1);
 
+#endif // TARGET_OS_EMBEDDED
+
 __END_DECLS
 
 #endif /* _CAPTIVENETWORK_H */
index 2a8b3907ea077ce81f564e0fdddf70cc3c702d14..873046dcc8696a6136258f55f22f5541e500bf49 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2003-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2001, 2003-2005, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -90,7 +90,7 @@ my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new)
     return;
 }
 
-static __inline__ CFStringRef
+static __inline__ CF_RETURNS_RETAINED CFStringRef
 S_application_path(CFStringRef applicationID)
 {
     return (CFStringCreateWithFormat(NULL, NULL,
@@ -240,19 +240,8 @@ SCDynamicStoreCopyDHCPInfo(SCDynamicStoreRef store, CFStringRef serviceID)
 {
     CFDictionaryRef    dhcp_dict = NULL;
     CFStringRef                key = NULL;
-    boolean_t          needs_close = FALSE;
     CFDictionaryRef    primary_dict = NULL;
 
-    if (store == NULL) {
-       needs_close = TRUE;
-       store = SCDynamicStoreCreate(NULL,
-                                    CFSTR("SCDynamicStoreCopyDHCPInfo"),
-                                    NULL, NULL);
-       if (store == NULL) {
-           goto done;
-       }
-    }
-
     if (serviceID == NULL) {
        /* get the primary service name */
        key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
@@ -287,9 +276,6 @@ SCDynamicStoreCopyDHCPInfo(SCDynamicStoreRef store, CFStringRef serviceID)
     if (primary_dict) {
        CFRelease(primary_dict);
     }
-    if (needs_close == TRUE && store != NULL) {
-       CFRelease(store);
-    }
     return (dhcp_dict);
 }
 
@@ -319,6 +305,12 @@ DHCPInfoGetLeaseStartTime(CFDictionaryRef dhcp_dict)
     return (CFDictionaryGetValue(dhcp_dict, CFSTR("LeaseStartTime")));
 }
 
+CFDateRef
+DHCPInfoGetLeaseExpirationTime(CFDictionaryRef dhcp_dict)
+{
+    return (CFDictionaryGetValue(dhcp_dict, CFSTR("LeaseExpirationTime")));
+}
+
 #ifdef TEST_DHCPCLIENT_PREFERENCES
 void
 print_data(u_char * data_p, int n_bytes)
@@ -626,5 +618,5 @@ main(int argc, char * argv[])
     exit(0);
     return(0);
 }
-#endif TEST_DHCPCLIENT_PREFERENCES
+#endif // TEST_DHCPCLIENT_PREFERENCES
 
index c88493feea4dfaf9435bd3213b51a8f79081c73c..2ea9adbd461f62b0138ef5fe896af55aabf9e37e 100644 (file)
Binary files a/SystemConfiguration.fproj/English.lproj/NetworkInterface.strings and b/SystemConfiguration.fproj/English.lproj/NetworkInterface.strings differ
index e39949325e97e91bdef7bc85ffe9b24715b3412c..f9008ac7aa79bcbfdd62c8300f4aa81d9894008a 100644 (file)
@@ -7,7 +7,7 @@
        <key>CFBundleExecutable</key>
        <string>SystemConfiguration</string>
        <key>CFBundleGetInfoString</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>CFBundleIdentifier</key>
        <string>com.apple.SystemConfiguration</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <key>CFBundlePackageType</key>
        <string>FMWK</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
 </dict>
 </plist>
index e39949325e97e91bdef7bc85ffe9b24715b3412c..f9008ac7aa79bcbfdd62c8300f4aa81d9894008a 100644 (file)
@@ -7,7 +7,7 @@
        <key>CFBundleExecutable</key>
        <string>SystemConfiguration</string>
        <key>CFBundleGetInfoString</key>
-       <string>1.11</string>
+       <string>1.12</string>
        <key>CFBundleIdentifier</key>
        <string>com.apple.SystemConfiguration</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <key>CFBundlePackageType</key>
        <string>FMWK</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.11.3</string>
+       <string>1.12</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.11</string>
+       <string>1.12</string>
 </dict>
 </plist>
index 5f92caa88ce8b2065cc5ee87158a7b6f814d72f4..43a21011d85dc399079ca73acc8f30bac68d5909 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -39,6 +39,7 @@
 
 #include <SystemConfiguration/SystemConfiguration.h>
 #include <SystemConfiguration/SCPrivate.h>
+#include "SCD.h"
 #include "SCDynamicStoreInternal.h"
 #include "config.h"            /* MiG generated file */
 
@@ -55,12 +56,6 @@ int  _sc_log         = TRUE;         /* 0 if SC messages should be written to stdout/stderr,
 #pragma mark Thread specific data
 
 
-typedef struct {
-       aslclient       _asl;
-       int             _sc_error;
-} __SCThreadSpecificData, *__SCThreadSpecificDataRef;
-
-
 static pthread_once_t  tsKeyInitialized        = PTHREAD_ONCE_INIT;
 static pthread_key_t   tsDataKey;
 
@@ -71,7 +66,8 @@ __SCThreadSpecificDataFinalize(void *arg)
        __SCThreadSpecificDataRef       tsd = (__SCThreadSpecificDataRef)arg;
 
        if (tsd != NULL) {
-               if (tsd->_asl    != NULL) asl_close(tsd->_asl);
+               if (tsd->_asl != NULL) asl_close(tsd->_asl);
+               if (tsd->_sc_store != NULL) CFRelease(tsd->_sc_store);
                CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
        }
        return;
@@ -86,7 +82,8 @@ __SCThreadSpecificKeyInitialize()
 }
 
 
-static __SCThreadSpecificDataRef
+__private_extern__
+__SCThreadSpecificDataRef
 __SCGetThreadSpecificData()
 {
        __SCThreadSpecificDataRef       tsd;
@@ -96,9 +93,9 @@ __SCGetThreadSpecificData()
        tsd = pthread_getspecific(tsDataKey);
        if (tsd == NULL) {
                tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0);
-               tsd->_asl = asl_open(NULL, NULL, 0);
-               asl_set_filter(tsd->_asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+               tsd->_asl = NULL;
                tsd->_sc_error = kSCStatusOK;
+               tsd->_sc_store = NULL;
                pthread_setspecific(tsDataKey, tsd);
        }
 
@@ -370,6 +367,10 @@ __SCLog(aslclient asl, aslmsg msg, int level, CFStringRef formatString, va_list
                __SCThreadSpecificDataRef       tsd;
 
                tsd = __SCGetThreadSpecificData();
+               if (tsd->_asl == NULL) {
+                       tsd->_asl = asl_open(NULL, NULL, 0);
+                       asl_set_filter(tsd->_asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+               }
                asl = tsd->_asl;
        }
 
diff --git a/SystemConfiguration.fproj/SCD.h b/SystemConfiguration.fproj/SCD.h
new file mode 100644 (file)
index 0000000..78a3c35
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCD_H
+#define _SCD_H
+
+#include <Availability.h>
+#include <TargetConditionals.h>
+#include <sys/cdefs.h>
+#include <asl.h>
+#include <SystemConfiguration/SCDynamicStore.h>
+
+
+typedef struct {
+       aslclient               _asl;
+       int                     _sc_error;
+       SCDynamicStoreRef       _sc_store;
+} __SCThreadSpecificData, *__SCThreadSpecificDataRef;
+
+
+
+__BEGIN_DECLS
+
+__SCThreadSpecificDataRef
+__SCGetThreadSpecificData              (void);
+
+__END_DECLS
+
+#endif /* _SCD_H */
index 74c9bd192c5fb9a9383f5fd15b775d0304007fc8..767277d9bcb69d416399294dfb83caff864afbe4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -89,21 +89,11 @@ SCDynamicStoreAddTemporaryValue(SCDynamicStoreRef store, CFStringRef key, CFProp
                             &newInstance,
                             (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreAddTemporaryValue configadd_s(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreAddTemporaryValue configadd_s()")) {
+               goto retry;
        }
 
        /* clean up */
@@ -121,7 +111,7 @@ SCDynamicStoreAddTemporaryValue(SCDynamicStoreRef store, CFStringRef key, CFProp
 Boolean
 SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        CFDataRef                       utfKey;         /* serialized key */
        xmlData_t                       myKeyRef;
@@ -133,11 +123,15 @@ SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListR
        int                             sc_status;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return FALSE;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                /* sorry, you must have an open session to play */
                _SCErrorSet(kSCStatusNoStoreServer);
@@ -168,21 +162,11 @@ SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListR
                           &newInstance,
                           (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreAddValue configadd(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreAddValue configadd()")) {
+               goto retry;
        }
 
        /* clean up */
index 0504412e4d68013441cda23cdee524c053d77c9b..58cb1c6a3fb40fb7b3e38d17bee433312418e837 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -86,18 +86,6 @@ SCDynamicStoreCopyConsoleUser(SCDynamicStoreRef      store,
        CFStringRef             consoleUser     = NULL;
        CFDictionaryRef         dict            = NULL;
        CFStringRef             key;
-       Boolean                 tempSession     = FALSE;
-
-       if (store == NULL) {
-               store = SCDynamicStoreCreate(NULL,
-                                            CFSTR("SCDynamicStoreCopyConsoleUser"),
-                                            NULL,
-                                            NULL);
-               if (store == NULL) {
-                       return NULL;
-               }
-               tempSession = TRUE;
-       }
 
        key  = SCDynamicStoreKeyCreateConsoleUser(NULL);
        dict = SCDynamicStoreCopyValue(store, key);
@@ -142,7 +130,6 @@ SCDynamicStoreCopyConsoleUser(SCDynamicStoreRef     store,
 
     done :
 
-       if (tempSession)        CFRelease(store);
        if (dict)               CFRelease(dict);
        return consoleUser;
 }
@@ -154,18 +141,6 @@ SCDynamicStoreCopyConsoleInformation(SCDynamicStoreRef store)
        CFDictionaryRef         dict            = NULL;
        CFArrayRef              info            = NULL;
        CFStringRef             key;
-       Boolean                 tempSession     = FALSE;
-
-       if (store == NULL) {
-               store = SCDynamicStoreCreate(NULL,
-                                            CFSTR("SCDynamicStoreCopyConsoleUser"),
-                                            NULL,
-                                            NULL);
-               if (store == NULL) {
-                       return NULL;
-               }
-               tempSession = TRUE;
-       }
 
        key  = SCDynamicStoreKeyCreateConsoleUser(NULL);
        dict = SCDynamicStoreCopyValue(store, key);
@@ -186,7 +161,6 @@ SCDynamicStoreCopyConsoleInformation(SCDynamicStoreRef store)
 
     done :
 
-       if (tempSession)        CFRelease(store);
        if (dict)               CFRelease(dict);
        return info;
 }
@@ -203,18 +177,6 @@ SCDynamicStoreSetConsoleInformation(SCDynamicStoreRef      store,
        CFMutableDictionaryRef  dict            = NULL;
        CFStringRef             key             = SCDynamicStoreKeyCreateConsoleUser(NULL);
        Boolean                 ok              = FALSE;
-       Boolean                 tempSession     = FALSE;
-
-       if (store == NULL) {
-               store = SCDynamicStoreCreate(NULL,
-                                            CFSTR("SCDynamicStoreSetConsoleUser"),
-                                            NULL,
-                                            NULL);
-               if (store == NULL) {
-                       goto done;
-               }
-               tempSession = TRUE;
-       }
 
        if ((user == NULL) && (sessions == NULL)) {
                ok = SCDynamicStoreRemoveValue(store, key);
@@ -252,7 +214,6 @@ SCDynamicStoreSetConsoleInformation(SCDynamicStoreRef       store,
 
        if (dict)               CFRelease(dict);
        if (key)                CFRelease(key);
-       if (tempSession)        CFRelease(store);
        return ok;
 }
 
@@ -268,18 +229,6 @@ SCDynamicStoreSetConsoleUser(SCDynamicStoreRef     store,
        CFStringRef             key             = SCDynamicStoreKeyCreateConsoleUser(NULL);
        CFNumberRef             num;
        Boolean                 ok              = FALSE;
-       Boolean                 tempSession     = FALSE;
-
-       if (store == NULL) {
-               store = SCDynamicStoreCreate(NULL,
-                                            CFSTR("SCDynamicStoreSetConsoleUser"),
-                                            NULL,
-                                            NULL);
-               if (store == NULL) {
-                       goto done;
-               }
-               tempSession = TRUE;
-       }
 
        if (user == NULL) {
                ok = SCDynamicStoreRemoveValue(store, key);
@@ -309,6 +258,5 @@ SCDynamicStoreSetConsoleUser(SCDynamicStoreRef      store,
 
        if (dict)               CFRelease(dict);
        if (key)                CFRelease(key);
-       if (tempSession)        CFRelease(store);
        return ok;
 }
index 9ce5a19775a4a4e7cf35f53a2008143ec0d9746f..16784d3d38dba5e190a5d5ac536bf93d884ba698 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -45,7 +45,7 @@ SCDynamicStoreCopyMultiple(SCDynamicStoreRef  store,
                           CFArrayRef           keys,
                           CFArrayRef           patterns)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        CFDataRef                       xmlKeys         = NULL; /* keys (XML serialized) */
        xmlData_t                       myKeysRef       = NULL; /* keys (serialized) */
@@ -60,11 +60,15 @@ SCDynamicStoreCopyMultiple(SCDynamicStoreRef        store,
        int                             sc_status;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return NULL;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return NULL;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                _SCErrorSet(kSCStatusNoStoreServer);
                return NULL;    /* you must have an open session to play */
@@ -99,21 +103,11 @@ SCDynamicStoreCopyMultiple(SCDynamicStoreRef       store,
                             &xmlDictLen,
                             (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCopyMultiple configget_m(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreCopyMultiple configget_m()")) {
+               goto retry;
        }
 
        /* clean up */
@@ -144,7 +138,7 @@ SCDynamicStoreCopyMultiple(SCDynamicStoreRef        store,
 CFPropertyListRef
 SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
 {
-       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        CFDataRef                       utfKey;                 /* key (XML serialized) */
        xmlData_t                       myKeyRef;               /* key (serialized) */
@@ -156,11 +150,15 @@ SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
        int                             sc_status;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return NULL;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return NULL;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                _SCErrorSet(kSCStatusNoStoreServer);
                return NULL;    /* you must have an open session to play */
@@ -183,21 +181,11 @@ SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
                           &newInstance,
                           (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCopyValue configget(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreCopyValue configget()")) {
+               goto retry;
        }
 
        /* clean up */
index 3a0e61f714c4bd8b7411a94a0d18a0ac5610e961..d16f6d109f957e74ef2849614db8c69da218b60b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -111,21 +111,9 @@ CFStringRef
 SCDynamicStoreCopyComputerName(SCDynamicStoreRef       store,
                               CFStringEncoding         *nameEncoding)
 {
-       CFDictionaryRef         dict;
+       CFDictionaryRef         dict            = NULL;
        CFStringRef             key;
        CFStringRef             name            = NULL;
-       Boolean                 tempSession     = FALSE;
-
-       if (store == NULL) {
-               store = SCDynamicStoreCreate(NULL,
-                                            CFSTR("SCDynamicStoreCopyComputerName"),
-                                            NULL,
-                                            NULL);
-               if (store == NULL) {
-                       return NULL;
-               }
-               tempSession = TRUE;
-       }
 
        key  = SCDynamicStoreKeyCreateComputerName(NULL);
        dict = SCDynamicStoreCopyValue(store, key);
@@ -166,7 +154,6 @@ SCDynamicStoreCopyComputerName(SCDynamicStoreRef    store,
 
     done :
 
-       if (tempSession)        CFRelease(store);
        if (dict != NULL)       CFRelease(dict);
        return name;
 }
@@ -404,21 +391,9 @@ SCDynamicStoreKeyCreateHostNames(CFAllocatorRef allocator)
 CFStringRef
 SCDynamicStoreCopyLocalHostName(SCDynamicStoreRef store)
 {
-       CFDictionaryRef         dict;
+       CFDictionaryRef         dict            = NULL;
        CFStringRef             key;
        CFStringRef             name            = NULL;
-       Boolean                 tempSession     = FALSE;
-
-       if (store == NULL) {
-               store = SCDynamicStoreCreate(NULL,
-                                            CFSTR("SCDynamicStoreCopyLocalHostName"),
-                                            NULL,
-                                            NULL);
-               if (store == NULL) {
-                       return NULL;
-               }
-               tempSession = TRUE;
-       }
 
        key  = SCDynamicStoreKeyCreateHostNames(NULL);
        dict = SCDynamicStoreCopyValue(store, key);
@@ -447,7 +422,6 @@ SCDynamicStoreCopyLocalHostName(SCDynamicStoreRef store)
 
     done :
 
-       if (tempSession)        CFRelease(store);
        if (dict != NULL)       CFRelease(dict);
        return name;
 }
index 5ba13bb4b96bf7db60d4cbc3131ee77a47534adf..f77c2190fea6fda7548c860c2f2bf87b17fdb76a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -42,7 +42,7 @@
 CFArrayRef
 SCDynamicStoreCopyKeyList(SCDynamicStoreRef store, CFStringRef pattern)
 {
-       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        CFDataRef                       utfPattern;             /* serialized pattern */
        xmlData_t                       myPatternRef;
@@ -53,11 +53,15 @@ SCDynamicStoreCopyKeyList(SCDynamicStoreRef store, CFStringRef pattern)
        CFArrayRef                      allKeys;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return NULL;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return NULL;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                _SCErrorSet(kSCStatusNoStoreServer);
                return NULL;
@@ -80,21 +84,11 @@ SCDynamicStoreCopyKeyList(SCDynamicStoreRef store, CFStringRef pattern)
                            &xmlDataLen,
                            (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCopyKeyList configlist(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreCopyKeyList configlist()")) {
+               goto retry;
        }
 
        /* clean up */
diff --git a/SystemConfiguration.fproj/SCDLock.c b/SystemConfiguration.fproj/SCDLock.c
deleted file mode 100644 (file)
index 90617fd..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * Modification History
- *
- * June 1, 2001                        Allan Nathanson <ajn@apple.com>
- * - public API conversion
- *
- * March 24, 2000              Allan Nathanson <ajn@apple.com>
- * - initial revision
- */
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCPrivate.h>
-#include "SCDynamicStoreInternal.h"
-#include "config.h"            /* MiG generated file */
-
-Boolean
-SCDynamicStoreLock(SCDynamicStoreRef store)
-{
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-       kern_return_t                   status;
-       int                             sc_status;
-
-       if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
-       }
-
-       if (storePrivate->server == MACH_PORT_NULL) {
-               /* sorry, you must have an open session to play */
-               _SCErrorSet(kSCStatusNoStoreServer);
-               return FALSE;
-       }
-
-    retry :
-
-       /* get the lock from the server */
-       status = configlock(storePrivate->server, (int *)&sc_status);
-
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreLock configlock(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
-       }
-
-       if (sc_status != kSCStatusOK) {
-               _SCErrorSet(sc_status);
-               return FALSE;
-       }
-
-       return TRUE;
-}
index 40b7569d11e9f8f000c4b526877c9096f392bcf7..901278cf190881d33836b2a3c0157cfb35483779 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -89,21 +89,11 @@ SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean is
                           isRegex,
                           (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreAddWatchedKey notifyadd(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreAddWatchedKey notifyadd()")) {
+               goto retry;
        }
 
        /* clean up */
index ca0454db9372db4c6e9a004fce4bf3a8fd685852..673f2a55a56f04faa1dd01b5b264f61ccbbde261 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2008-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2008-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -56,25 +56,6 @@ SCDynamicStoreNotifyCancel(SCDynamicStoreRef store)
                case NotifierNotRegistered :
                        /* if no notifications have been registered */
                        return TRUE;
-               case Using_NotifierInformViaCallback :
-                       /* invalidate and release the run loop source */
-                       if (storePrivate->callbackRLS != NULL) {
-                               CFRunLoopSourceInvalidate(storePrivate->callbackRLS);
-                               CFRelease(storePrivate->callbackRLS);
-                               storePrivate->callbackRLS = NULL;
-                       }
-
-                       /* invalidate and release the callback mach port */
-                       if (storePrivate->callbackPort != NULL) {
-                               __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreNotifyCancel", CFMachPortGetPort(storePrivate->callbackPort));
-                               CFMachPortInvalidate(storePrivate->callbackPort);
-                               CFRelease(storePrivate->callbackPort);
-                               storePrivate->callbackPort = NULL;
-                       }
-
-                       storePrivate->callbackArgument  = NULL;
-                       storePrivate->callbackFunction  = NULL;
-                       break;
                case Using_NotifierInformViaRunLoop :
                        CFRunLoopSourceInvalidate(storePrivate->rls);
                        storePrivate->rls = NULL;
@@ -93,21 +74,12 @@ SCDynamicStoreNotifyCancel(SCDynamicStoreRef store)
        }
 
        status = notifycancel(storePrivate->server, (int *)&sc_status);
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCancel notifycancel(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if (((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED))
-                   && __SCDynamicStoreReconnect(store)) {
-                       sc_status = kSCStatusOK;
-               } else {
-                       sc_status = status;
-               }
+
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreNotifyCancel notifycancel()")) {
+               sc_status = kSCStatusOK;
        }
 
     done :
index bbfe5e4a6e0a86702c1aef9a88b92f018cfdfc78..cb8b7cc9ccee2829b2e38a3bdbae271d7c060e38 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -68,21 +68,11 @@ SCDynamicStoreCopyNotifiedKeys(SCDynamicStoreRef store)
                               &xmlDataLen,
                               (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCopyNotifiedKeys notifychanges(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreCopyNotifiedKeys notifychanges()")) {
+               goto retry;
        }
 
        if (sc_status != kSCStatusOK) {
index 166c0ced1744a74a49a982ac0d1df8958c4719a0..cf3ec8ec4c5db1084dba5f73a0238f4a097c2285 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2008-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2008-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include "config.h"            /* MiG generated file */
 
 
-static void
-informCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
-{
-       SCDynamicStoreRef               store           = (SCDynamicStoreRef)info;
-       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
-       mach_no_senders_notification_t  *buf            = msg;
-       mach_msg_id_t                   msgid           = buf->not_header.msgh_id;
-       SCDynamicStoreCallBack_v1       cbFunc          = storePrivate->callbackFunction;
-       void                            *cbArg          = storePrivate->callbackArgument;
-
-       if (msgid == MACH_NOTIFY_NO_SENDERS) {
-               /* the server died, disable additional callbacks */
-#ifdef DEBUG
-               SCLog(_sc_verbose, LOG_DEBUG, CFSTR("  notifier port closed, disabling notifier"));
-#endif /* DEBUG */
-       } else if (cbFunc == NULL) {
-               /* there is no (longer) a callback function, disable additional callbacks */
-#ifdef DEBUG
-               SCLog(_sc_verbose, LOG_DEBUG, CFSTR("  no callback function, disabling notifier"));
-#endif /* DEBUG */
-       } else {
-#ifdef DEBUG
-               SCLog(_sc_verbose, LOG_DEBUG, CFSTR("  executing notification function"));
-#endif /* DEBUG */
-               if ((*cbFunc)(store, cbArg)) {
-                       /*
-                        * callback function returned success.
-                        */
-                       return;
-               } else {
-#ifdef DEBUG
-                       SCLog(_sc_verbose, LOG_DEBUG, CFSTR("  callback returned error, disabling notifier"));
-#endif /* DEBUG */
-               }
-       }
-
-#ifdef DEBUG
-       if (port != storePrivate->callbackPort) {
-               SCLog(_sc_verbose, LOG_DEBUG, CFSTR("informCallback, why is port != callbackPort?"));
-       }
-#endif /* DEBUG */
-
-       /* invalidate the run loop source */
-       if (storePrivate->callbackRLS != NULL) {
-               CFRunLoopSourceInvalidate(storePrivate->callbackRLS);
-               CFRelease(storePrivate->callbackRLS);
-               storePrivate->callbackRLS = NULL;
-       }
-
-       /* invalidate port */
-       if (storePrivate->callbackPort != NULL) {
-               __MACH_PORT_DEBUG(TRUE, "*** informCallback", CFMachPortGetPort(storePrivate->callbackPort));
-               CFMachPortInvalidate(storePrivate->callbackPort);
-               CFRelease(storePrivate->callbackPort);
-               storePrivate->callbackPort = NULL;
-       }
-
-       /* disable notifier */
-       storePrivate->notifyStatus      = NotifierNotRegistered;
-       storePrivate->callbackArgument  = NULL;
-       storePrivate->callbackFunction  = NULL;
-
-       return;
-}
-
-
 static CFStringRef
 notifyMPCopyDescription(const void *info)
 {
@@ -122,141 +56,6 @@ notifyMPCopyDescription(const void *info)
 }
 
 
-Boolean
-SCDynamicStoreNotifyCallback(SCDynamicStoreRef         store,
-                            CFRunLoopRef               runLoop,
-                            SCDynamicStoreCallBack_v1  func,
-                            void                       *arg)
-{
-       CFMachPortContext               context         = { 0
-                                                         , (void *)store
-                                                         , CFRetain
-                                                         , CFRelease
-                                                         , notifyMPCopyDescription
-                                                         };
-       mach_port_t                     oldNotify;
-       mach_port_t                     port;
-       int                             sc_status;
-       kern_return_t                   status;
-       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
-
-       if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
-       }
-
-       if (storePrivate->server == MACH_PORT_NULL) {
-               /* sorry, you must have an open session to play */
-               _SCErrorSet(kSCStatusNoStoreServer);
-               return FALSE;
-       }
-
-       if (storePrivate->notifyStatus != NotifierNotRegistered) {
-               /* sorry, you can only have one notification registered at once */
-               _SCErrorSet(kSCStatusNotifierActive);
-               return FALSE;
-       }
-
-       /* Allocating port (for server response) */
-       status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
-       if (status != KERN_SUCCESS) {
-               SCLog(TRUE, LOG_ERR, CFSTR("mach_port_allocate(): %s"), mach_error_string(status));
-               _SCErrorSet(status);
-               return FALSE;
-       }
-
-       status = mach_port_insert_right(mach_task_self(),
-                                       port,
-                                       port,
-                                       MACH_MSG_TYPE_MAKE_SEND);
-       if (status != KERN_SUCCESS) {
-               /*
-                * We can't insert a send right into our own port!  This should
-                * only happen if someone stomped on OUR port (so let's leave
-                * the port alone).
-                */
-               SCLog(TRUE, LOG_ERR, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status));
-               _SCErrorSet(status);
-               return FALSE;
-       }
-
-       /* Request a notification when/if the server dies */
-       status = mach_port_request_notification(mach_task_self(),
-                                               port,
-                                               MACH_NOTIFY_NO_SENDERS,
-                                               1,
-                                               port,
-                                               MACH_MSG_TYPE_MAKE_SEND_ONCE,
-                                               &oldNotify);
-       if (status != KERN_SUCCESS) {
-               /*
-                * We can't request a notification for our own port!  This should
-                * only happen if someone stomped on OUR port (so let's leave
-                * the port alone).
-                */
-               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback mach_port_request_notification(): %s"), mach_error_string(status));
-               _SCErrorSet(status);
-               return FALSE;
-       }
-
-       if (oldNotify != MACH_PORT_NULL) {
-               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback(): oldNotify != MACH_PORT_NULL"));
-       }
-
-    retry :
-
-       /* Requesting notification via mach port */
-       status = notifyviaport(storePrivate->server,
-                              port,
-                              0,
-                              (int *)&sc_status);
-
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback notifyviaport(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-                       /* remove the send right that we tried (but failed) to pass to the server */
-                       (void) mach_port_deallocate(mach_task_self(), port);
-               }
-
-               /* remove our receive right  */
-               (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1);
-               sc_status = status;
-       }
-
-       if (sc_status != kSCStatusOK) {
-               _SCErrorSet(sc_status);
-               return FALSE;
-       }
-
-       /* set notifier active */
-       storePrivate->notifyStatus      = Using_NotifierInformViaCallback;
-
-       /* Creating/adding a run loop source for the port */
-       __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreNotifyCallback", port);
-       storePrivate->callbackArgument  = arg;
-       storePrivate->callbackFunction  = func;
-       storePrivate->callbackPort      = _SC_CFMachPortCreateWithPort("SCDynamicStoreNotifyCallback",
-                                                                      port,
-                                                                      informCallback,
-                                                                      &context);
-       storePrivate->callbackRLS       = CFMachPortCreateRunLoopSource(NULL, storePrivate->callbackPort, 0);
-       CFRunLoopAddSource(runLoop, storePrivate->callbackRLS, kCFRunLoopDefaultMode);
-
-       return TRUE;
-}
-
-
 static void
 rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
 {
@@ -272,8 +71,8 @@ rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
 #endif /* DEBUG */
 
 #ifdef DEBUG
-               if (port != storePrivate->callbackPort) {
-                       SCLog(_sc_verbose, LOG_DEBUG, CFSTR("rlsCallback(), why is port != callbackPort?"));
+               if (port != storePrivate->rlsNotifyPort) {
+                       SCLog(_sc_verbose, LOG_DEBUG, CFSTR("rlsCallback(), why is port != rlsNotifyPort?"));
                }
 #endif /* DEBUG */
 
@@ -374,19 +173,16 @@ rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode)
 
                __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule", port);
                status = notifyviaport(storePrivate->server, port, 0, (int *)&sc_status);
+
+               if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                            status,
+                                                            &sc_status,
+                                                            "rlsSchedule notifyviaport()")) {
+                       goto retry;
+               }
+
                if (status != KERN_SUCCESS) {
                        if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                               /* the server's gone and our session port's dead, remove the dead name right */
-                               (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-                       } else {
-                               /* we got an unexpected error, leave the [session] port alone */
-                               SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule notifyviaport(): %s"), mach_error_string(status));
-                       }
-                       storePrivate->server = MACH_PORT_NULL;
-                       if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                               if (__SCDynamicStoreReconnect(store)) {
-                                       goto retry;
-                               }
                                /* remove the send right that we tried (but failed) to pass to the server */
                                (void) mach_port_deallocate(mach_task_self(), port);
                        }
@@ -403,23 +199,23 @@ rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode)
                }
 
                __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after notifyviaport)", port);
-               storePrivate->callbackPort = _SC_CFMachPortCreateWithPort("SCDynamicStore",
-                                                                         port,
-                                                                         rlsCallback,
-                                                                         &context);
-               CFMachPortSetInvalidationCallBack(storePrivate->callbackPort, portInvalidate);
-               storePrivate->callbackRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->callbackPort, 0);
+               storePrivate->rlsNotifyPort = _SC_CFMachPortCreateWithPort("SCDynamicStore",
+                                                                    port,
+                                                                    rlsCallback,
+                                                                    &context);
+               CFMachPortSetInvalidationCallBack(storePrivate->rlsNotifyPort, portInvalidate);
+               storePrivate->rlsNotifyRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->rlsNotifyPort, 0);
 
                storePrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        }
 
-       if ((rl != NULL) && (storePrivate->callbackRLS != NULL)) {
+       if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) {
                if (!_SC_isScheduled(store, rl, mode, storePrivate->rlList)) {
                        /*
                         * if we are not already scheduled with this runLoop / runLoopMode
                         */
-                       CFRunLoopAddSource(rl, storePrivate->callbackRLS, mode);
-                       __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->callbackPort));
+                       CFRunLoopAddSource(rl, storePrivate->rlsNotifyRLS, mode);
+                       __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->rlsNotifyPort));
                }
 
                _SC_schedule(store, rl, mode, storePrivate->rlList);
@@ -442,7 +238,7 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode)
              (rl != NULL) ? mode : CFSTR("libdispatch"));
 #endif /* DEBUG */
 
-       if ((rl != NULL) && (storePrivate->callbackRLS != NULL)) {
+       if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) {
                if (_SC_unschedule(store, rl, mode, storePrivate->rlList, FALSE)) {
                        /*
                         * if currently scheduled on this runLoop / runLoopMode
@@ -453,7 +249,7 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode)
                                 * if we are no longer scheduled to receive notifications for
                                 * this runLoop / runLoopMode
                                 */
-                               CFRunLoopRemoveSource(rl, storePrivate->callbackRLS, mode);
+                               CFRunLoopRemoveSource(rl, storePrivate->rlsNotifyRLS, mode);
                        }
                }
        }
@@ -465,44 +261,41 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode)
 #ifdef DEBUG
                SCLog(_sc_verbose, LOG_DEBUG, CFSTR("  cancel callback runloop source"));
 #endif /* DEBUG */
-               __MACH_PORT_DEBUG((storePrivate->callbackPort != NULL),
+               __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL),
                                  "*** rlsCancel",
-                                 CFMachPortGetPort(storePrivate->callbackPort));
+                                 CFMachPortGetPort(storePrivate->rlsNotifyPort));
 
-               CFRelease(storePrivate->rlList);
-               storePrivate->rlList = NULL;
+               if (storePrivate->rlList != NULL) {
+                       CFRelease(storePrivate->rlList);
+                       storePrivate->rlList = NULL;
+               }
 
-               if (storePrivate->callbackRLS != NULL) {
+               if (storePrivate->rlsNotifyRLS != NULL) {
                        /* invalidate & remove the run loop source */
-                       CFRunLoopSourceInvalidate(storePrivate->callbackRLS);
-                       CFRelease(storePrivate->callbackRLS);
-                       storePrivate->callbackRLS = NULL;
+                       CFRunLoopSourceInvalidate(storePrivate->rlsNotifyRLS);
+                       CFRelease(storePrivate->rlsNotifyRLS);
+                       storePrivate->rlsNotifyRLS = NULL;
                }
 
-               if (storePrivate->callbackPort != NULL) {
+               if (storePrivate->rlsNotifyPort != NULL) {
                        /* invalidate port */
-                       __MACH_PORT_DEBUG((storePrivate->callbackPort != NULL),
+                       __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL),
                                          "*** rlsCancel (before invalidating CFMachPort)",
-                                         CFMachPortGetPort(storePrivate->callbackPort));
-                       CFMachPortInvalidate(storePrivate->callbackPort);
-                       CFRelease(storePrivate->callbackPort);
-                       storePrivate->callbackPort = NULL;
+                                         CFMachPortGetPort(storePrivate->rlsNotifyPort));
+                       CFMachPortInvalidate(storePrivate->rlsNotifyPort);
+                       CFRelease(storePrivate->rlsNotifyPort);
+                       storePrivate->rlsNotifyPort = NULL;
                }
 
                if (storePrivate->server != MACH_PORT_NULL) {
                        status = notifycancel(storePrivate->server, (int *)&sc_status);
+
+                       (void) __SCDynamicStoreCheckRetryAndHandleError(store,
+                                                                       status,
+                                                                       &sc_status,
+                                                                       "rlsCancel notifycancel()");
+
                        if (status != KERN_SUCCESS) {
-                               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                                       /* the server's gone and our session port's dead, remove the dead name right */
-                                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-                               } else {
-                                       /* we got an unexpected error, leave the [session] port alone */
-                                       SCLog(TRUE, LOG_ERR, CFSTR("rlsCancel notifycancel(): %s"), mach_error_string(status));
-                               }
-                               storePrivate->server = MACH_PORT_NULL;
-                               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                                       (void) __SCDynamicStoreReconnect(store);
-                               }
                                return;
                        }
                }
@@ -638,9 +431,6 @@ rlsCopyDescription(const void *info)
                }
                CFStringAppendFormat(result, NULL, CFSTR(", context = %@"), description);
                CFRelease(description);
-       } else {
-               CFStringAppendFormat(result, NULL, CFSTR(", callout = %p"), storePrivate->callbackFunction);
-               CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->callbackArgument);
        }
        CFStringAppendFormat(result, NULL, CFSTR("}"));
 
@@ -703,151 +493,160 @@ SCDynamicStoreCreateRunLoopSource(CFAllocatorRef        allocator,
 }
 
 
-static boolean_t
-SCDynamicStoreNotifyMIGCallback(mach_msg_header_t *message, mach_msg_header_t *reply)
-{
-       mach_msg_empty_rcv_t    *buf    = (mach_msg_empty_rcv_t *)message;
-       mach_msg_id_t           msgid   = buf->header.msgh_id;
-       SCDynamicStoreRef       store;
-
-       store = dispatch_get_context(dispatch_get_current_queue());
-       if (store != NULL) {
-               SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
-
-               CFRetain(storePrivate);
-               dispatch_async(storePrivate->dispatchQueue, ^{
-                       if (msgid == MACH_NOTIFY_NO_SENDERS) {
-                               /* re-establish notification and inform the client */
-                               (void)__SCDynamicStoreReconnectNotifications(store);
-                       }
-                       rlsPerform(storePrivate);
-                       CFRelease(storePrivate);
-               });
-       }
-       reply->msgh_remote_port = MACH_PORT_NULL;
-       return false;
-}
-
-
 Boolean
 SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store, dispatch_queue_t queue)
 {
+       dispatch_group_t                drainGroup      = NULL;
+       dispatch_queue_t                drainQueue      = NULL;
+       mach_port_t                     mp;
        Boolean                         ok              = FALSE;
+       dispatch_source_t               source;
        SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
+               // sorry, you must provide a session
                _SCErrorSet(kSCStatusNoStoreSession);
                return FALSE;
        }
 
-       if (queue != NULL) {
-               mach_port_t     mp;
-
-               if (storePrivate->server == MACH_PORT_NULL) {
-                       /* sorry, you must have an open session to play */
-                       _SCErrorSet(kSCStatusNoStoreServer);
-                       return FALSE;
-               }
-
-               if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) {
+       if (queue == NULL) {
+               if (storePrivate->dispatchQueue == NULL) {
                        _SCErrorSet(kSCStatusInvalidArgument);
                        return FALSE;
                }
 
-               if (storePrivate->notifyStatus != NotifierNotRegistered) {
-                       /* sorry, you can only have one notification registered at once... */
-                       _SCErrorSet(kSCStatusNotifierActive);
-                       return FALSE;
-               }
+               ok = TRUE;
+               goto cleanup;
+       }
 
-               /*
-                * mark our using of the SCDynamicStore notifications, create and schedule
-                * the notification port (storePrivate->callbackPort), and a bunch of other
-                * "setup"
-                */
-               storePrivate->notifyStatus = Using_NotifierInformViaDispatch;
-               rlsSchedule((void*)store, NULL, NULL);
-               storePrivate->dispatchQueue = queue;
-               dispatch_retain(storePrivate->dispatchQueue);
-
-               if (storePrivate->callbackPort == NULL) {
-                       /* if we could not schedule the notification */
-                       _SCErrorSet(kSCStatusFailed);
-                       goto cleanup;
-               }
+       if (storePrivate->server == MACH_PORT_NULL) {
+               // sorry, you must have an open session to play
+               _SCErrorSet(kSCStatusNoStoreServer);
+               return FALSE;
+       }
 
-               /*
-                * create a dispatch queue for the mach notifications source, we'll use
-                * this queue's context to carry the store pointer for the callback code.
-                */
-               storePrivate->callbackQueue = dispatch_queue_create("com.apple.SCDynamicStore.notifications", NULL);
-               if (storePrivate->callbackQueue == NULL){
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_queue_create() failed"));
-                       _SCErrorSet(kSCStatusFailed);
-                       goto cleanup;
-               }
-               CFRetain(store);        // Note: will be released when the dispatch queue is released
-               dispatch_set_context(storePrivate->callbackQueue, (void *)store);
-               dispatch_set_finalizer_f(storePrivate->callbackQueue, (dispatch_function_t)CFRelease);
-
-               /*
-                * create a dispatch source for the mach notifications
-                */
-               mp = CFMachPortGetPort(storePrivate->callbackPort);
-               storePrivate->callbackSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
-                                                                     mp,
-                                                                     0,
-                                                                     storePrivate->callbackQueue);
-               if (storePrivate->callbackSource == NULL) {
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed"));
-                       _SCErrorSet(kSCStatusFailed);
-                       goto cleanup;
+       if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (storePrivate->notifyStatus != NotifierNotRegistered) {
+               // sorry, you can only have one notification registered at once...
+               _SCErrorSet(kSCStatusNotifierActive);
+               return FALSE;
+       }
+
+       /*
+        * mark our using of the SCDynamicStore notifications, create and schedule
+        * the notification port (storePrivate->rlsNotifyPort), and a bunch of other
+        * "setup"
+        */
+       storePrivate->notifyStatus = Using_NotifierInformViaDispatch;
+       rlsSchedule((void*)store, NULL, NULL);
+       if (storePrivate->rlsNotifyPort == NULL) {
+               /* if we could not schedule the notification */
+               _SCErrorSet(kSCStatusFailed);
+               goto cleanup;
+       }
+
+       // retain the dispatch queue
+       storePrivate->dispatchQueue = queue;
+       dispatch_retain(storePrivate->dispatchQueue);
+
+       //
+       // We've taken a reference to the callers dispatch_queue and we
+       // want to hold on to that reference until we've processed any/all
+       // notifications.  To facilitate this we create a group, dispatch
+       // any notification blocks to via that group, and when the caller
+       // has told us to stop the notifications (unschedule) we wait for
+       // the group to empty and use the group's finalizer to release
+       // our reference to the SCDynamicStore.
+       //
+       storePrivate->dispatchGroup = dispatch_group_create();
+       CFRetain(store);
+       dispatch_set_context(storePrivate->dispatchGroup, (void *)store);
+       dispatch_set_finalizer_f(storePrivate->dispatchGroup, (dispatch_function_t)CFRelease);
+
+       // create a dispatch source for the mach notifications
+       mp = CFMachPortGetPort(storePrivate->rlsNotifyPort);
+       source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue);
+       if (source == NULL) {
+               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed"));
+               _SCErrorSet(kSCStatusFailed);
+               goto cleanup;
+       }
+
+       dispatch_source_set_event_handler(source, ^{
+               kern_return_t   kr;
+               mach_msg_id_t   msgid;
+               union {
+                       u_int8_t                        buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE];
+                       mach_msg_empty_rcv_t            msg;
+                       mach_no_senders_notification_t  no_senders;
+               } notify_msg;
+
+               kr = mach_msg(&notify_msg.msg.header,   // msg
+                             MACH_RCV_MSG,             // options
+                             0,                        // send_size
+                             sizeof(notify_msg),       // rcv_size
+                             mp,                       // rcv_name
+                             MACH_MSG_TIMEOUT_NONE,    // timeout
+                             MACH_PORT_NULL);          // notify
+               if (kr != KERN_SUCCESS) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("SCDynamicStore notification handler, kr=0x%x"),
+                             kr);
+                       return;
                }
-               dispatch_source_set_event_handler(storePrivate->callbackSource, ^{
-                       union MaxMsgSize {
-                               mach_msg_empty_rcv_t            normal;
-                               mach_no_senders_notification_t  no_senders;
-                       };
-
-                       dispatch_mig_server(storePrivate->callbackSource,
-                                           sizeof(union MaxMsgSize),
-                                           SCDynamicStoreNotifyMIGCallback);
+
+               msgid = notify_msg.msg.header.msgh_id;
+
+               CFRetain(store);
+               dispatch_group_async(storePrivate->dispatchGroup, storePrivate->dispatchQueue, ^{
+                       if (msgid == MACH_NOTIFY_NO_SENDERS) {
+                               // re-establish notification and inform the client
+                               (void)__SCDynamicStoreReconnectNotifications(store);
+                       }
+                       rlsPerform(storePrivate);
+                       CFRelease(store);
                });
-               dispatch_resume(storePrivate->callbackSource);
+       });
 
-               ok = TRUE;
-               goto done;
-       } else {
-               if (storePrivate->dispatchQueue == NULL) {
-                       _SCErrorSet(kSCStatusInvalidArgument);
-                       return FALSE;
-               }
+       dispatch_source_set_cancel_handler(source, ^{
+               dispatch_release(source);
+       });
 
-               ok = TRUE;
-       }
+       storePrivate->dispatchSource = source;
+       dispatch_resume(source);
+
+       return TRUE;
 
     cleanup :
 
-       if (storePrivate->callbackSource != NULL) {
-               dispatch_source_cancel(storePrivate->callbackSource);
-               if (storePrivate->callbackQueue != dispatch_get_current_queue()) {
-                       // ensure the cancellation has completed
-                       dispatch_sync(storePrivate->callbackQueue, ^{});
-               }
-               dispatch_release(storePrivate->callbackSource);
-               storePrivate->callbackSource = NULL;
-       }
-       if (storePrivate->callbackQueue != NULL) {
-               dispatch_release(storePrivate->callbackQueue);
-               storePrivate->callbackQueue = NULL;
+       CFRetain(store);
+
+       if (storePrivate->dispatchSource != NULL) {
+               dispatch_source_cancel(storePrivate->dispatchSource);
+               storePrivate->dispatchSource = NULL;
        }
-       dispatch_release(storePrivate->dispatchQueue);
+       drainGroup = storePrivate->dispatchGroup;
+       storePrivate->dispatchGroup = NULL;
+       drainQueue = storePrivate->dispatchQueue;
        storePrivate->dispatchQueue = NULL;
+
        rlsCancel((void*)store, NULL, NULL);
+
+       if (drainGroup != NULL) {
+               dispatch_group_notify(drainGroup, drainQueue, ^{
+                       // release group/queue references
+                       dispatch_release(drainQueue);
+                       dispatch_release(drainGroup);   // releases our store reference
+               });
+       }
+
        storePrivate->notifyStatus = NotifierNotRegistered;
 
-    done :
+       CFRelease(store);
 
        return ok;
 }
index f1b6f65af85df38b3ece11a5777828e083b6c4af..f5505cec8946bce096b46a40dd43ba2658299c8b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2004, 2005, 2008-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004, 2005, 2008-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -126,20 +126,14 @@ SCDynamicStoreNotifyFileDescriptor(SCDynamicStoreRef      store,
                             identifier,
                             (int *)&sc_status);
 
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreNotifyFileDescriptor notifyviafd()")) {
+               goto retry;
+       }
+
        if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyFileDescriptor notifyviafd(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
                _SCErrorSet(status);
                return FALSE;
        }
diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c b/SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c
deleted file mode 100644 (file)
index 4d0f145..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * Modification History
- *
- * June 1, 2001                        Allan Nathanson <ajn@apple.com>
- * - public API conversion
- *
- * March 31, 2000              Allan Nathanson <ajn@apple.com>
- * - initial revision
- */
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCPrivate.h>
-#include "SCDynamicStoreInternal.h"
-#include "config.h"            /* MiG generated file */
-
-Boolean
-SCDynamicStoreNotifyMachPort(SCDynamicStoreRef store, mach_msg_id_t identifier, mach_port_t *port)
-{
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-       kern_return_t                   status;
-       mach_port_t                     oldNotify;
-       int                             sc_status;
-
-       if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
-       }
-
-       if (storePrivate->server == MACH_PORT_NULL) {
-               /* sorry, you must have an open session to play */
-               _SCErrorSet(kSCStatusNoStoreServer);
-               return FALSE;
-       }
-
-       if (storePrivate->notifyStatus != NotifierNotRegistered) {
-               /* sorry, you can only have one notification registered at once */
-               _SCErrorSet(kSCStatusNotifierActive);
-               return FALSE;
-       }
-
-       /* Allocating port (for server response) */
-       status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, port);
-       if (status != KERN_SUCCESS) {
-               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort mach_port_allocate(): %s"), mach_error_string(status));
-               _SCErrorSet(status);
-               return FALSE;
-       }
-
-       status = mach_port_insert_right(mach_task_self(),
-                                       *port,
-                                       *port,
-                                       MACH_MSG_TYPE_MAKE_SEND);
-       if (status != KERN_SUCCESS) {
-               /*
-                * We can't insert a send right into our own port!  This should
-                * only happen if someone stomped on OUR port (so let's leave
-                * the port alone).
-                */
-               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort mach_port_insert_right(): %s"), mach_error_string(status));
-               *port = MACH_PORT_NULL;
-               _SCErrorSet(status);
-               return FALSE;
-       }
-
-       /* Request a notification when/if the server dies */
-       status = mach_port_request_notification(mach_task_self(),
-                                               *port,
-                                               MACH_NOTIFY_NO_SENDERS,
-                                               1,
-                                               *port,
-                                               MACH_MSG_TYPE_MAKE_SEND_ONCE,
-                                               &oldNotify);
-       if (status != KERN_SUCCESS) {
-               /*
-                * We can't request a notification for our own port!  This should
-                * only happen if someone stomped on OUR port (so let's leave
-                * the port alone).
-                */
-               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort mach_port_request_notification(): %s"), mach_error_string(status));
-               *port = MACH_PORT_NULL;
-               _SCErrorSet(status);
-               return FALSE;
-       }
-
-       if (oldNotify != MACH_PORT_NULL) {
-               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort(): oldNotify != MACH_PORT_NULL"));
-       }
-
-    retry :
-
-       status = notifyviaport(storePrivate->server,
-                              *port,
-                              identifier,
-                              (int *)&sc_status);
-
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort notifyviaport(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-                       /* remove the send right that we tried (but failed) to pass to the server */
-                       (void) mach_port_deallocate(mach_task_self(), *port);
-               }
-
-               /* remove our receive right  */
-               (void) mach_port_mod_refs(mach_task_self(), *port, MACH_PORT_RIGHT_RECEIVE, -1);
-               *port = MACH_PORT_NULL;
-               _SCErrorSet(status);
-               return FALSE;
-       }
-
-       /* set notifier active */
-       __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreNotifyMachPort", *port);
-       storePrivate->notifyStatus = Using_NotifierInformViaMachPort;
-
-       return TRUE;
-}
index 3b81fc8fb68b14bdc24b2f3a29ff58ac9002bf2b..ddae17a94852d1c6fb443a04f94691b43c1b4dd1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004, 2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -76,20 +76,14 @@ SCDynamicStoreNotifySignal(SCDynamicStoreRef store, pid_t pid, int sig)
 
        status = notifyviasignal(storePrivate->server, task, sig, (int *)&sc_status);
 
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreNotifySignal notifyviasignal()")) {
+               goto retry;
+       }
+
        if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifySignal notifyviasignal(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
                _SCErrorSet(status);
                return FALSE;
        }
index be63da6e820d10beccf0b1129c5d0e8172ab58ee..739f4e85a7dfbe7c2c6a1c8b6dc35c131639fd24 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -99,21 +99,11 @@ SCDynamicStoreRemoveWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean
                              isRegex,
                              (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreRemoveWatchedKey notifyremove(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreRemoveWatchedKey notifyremove()")) {
+               goto retry;
        }
 
        /* clean up */
index 23777fa4cf5813d5857e9727656241f3acd06b63..1ffb86330ad369ace8f96acfa31bd816d2289d26 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -91,21 +91,11 @@ SCDynamicStoreSetNotificationKeys(SCDynamicStoreRef store,
                           myPatternsLen,
                           (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetNotificationKeys notifyset(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreSetNotificationKeys notifyset()")) {
+               goto retry;
        }
 
        /* clean up */
index 707fc823d79c64d85da99f0604069a2eb3c68b8f..751f47f33516626bd73331b26ca084ef943da6a2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2004, 2006, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004, 2006, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -145,26 +145,21 @@ SCDynamicStoreNotifyWait(SCDynamicStoreRef store)
                               0,
                               (int *)&sc_status);
 
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreNotifyWait notifyviaport()")) {
+               goto retry;
+       }
+
        if (status != KERN_SUCCESS) {
                if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyWait notifyviaport(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
                        /* remove the send right that we tried (but failed) to pass to the server */
                        (void) mach_port_deallocate(mach_task_self(), port);
                }
 
                /* remove our receive right  */
                (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1);
-               sc_status = status;
        }
 
        if (sc_status != kSCStatusOK) {
@@ -203,21 +198,11 @@ SCDynamicStoreNotifyWait(SCDynamicStoreRef store)
        status = notifycancel(storePrivate->server,
                              (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyWait notifycancel(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if (((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) &&
-                   __SCDynamicStoreReconnect(store)) {
-                       sc_status = kSCStatusOK;
-               } else {
-                       sc_status = status;
-               }
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreNotifyWait notifycancel()")) {
+               sc_status = kSCStatusOK;
        }
 
        /* remove our receive right  */
index 36394bf1616a2aefc282d9c97513f558ec879ad7..d55a46e91177fd04b3073aa7702d3395b0462795 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -40,7 +40,7 @@ Boolean
 SCDynamicStoreNotifyValue(SCDynamicStoreRef    store,
                          CFStringRef           key)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        CFDataRef                       utfKey;         /* serialized key */
        xmlData_t                       myKeyRef;
@@ -48,11 +48,15 @@ SCDynamicStoreNotifyValue(SCDynamicStoreRef store,
        int                             sc_status;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return FALSE;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                /* sorry, you must have an open session to play */
                _SCErrorSet(kSCStatusNoStoreServer);
@@ -73,21 +77,11 @@ SCDynamicStoreNotifyValue(SCDynamicStoreRef store,
                              myKeyLen,
                              (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyValue confignotify(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreNotifyValue confignotify()")) {
+               goto retry;
        }
 
        /* clean up */
index f21d49c607fe84ca81ced45aa5e9abb8cc05bb77..c8090bb04b28a5cfc93d855df3f592656cac4c07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2006, 2008-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2006, 2008-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include <SystemConfiguration/SystemConfiguration.h>
 #include <SystemConfiguration/SCPrivate.h>
+#include "SCD.h"
 #include "SCDynamicStoreInternal.h"
 #include "config.h"            /* MiG generated file */
 
 
-static CFStringRef     _sc_bundleID    = NULL;
-static pthread_mutex_t _sc_lock        = PTHREAD_MUTEX_INITIALIZER;
-static mach_port_t     _sc_server      = MACH_PORT_NULL;
+static CFStringRef             _sc_bundleID    = NULL;
+static pthread_mutex_t         _sc_lock        = PTHREAD_MUTEX_INITIALIZER;
+static mach_port_t             _sc_server      = MACH_PORT_NULL;
 
 
 static const char      *notifyType[] = {
@@ -76,9 +77,6 @@ __SCDynamicStoreCopyDescription(CFTypeRef cf) {
        } else {
                CFStringAppendFormat(result, NULL, CFSTR("server not (no longer) available"));
        }
-       if (storePrivate->locked) {
-               CFStringAppendFormat(result, NULL, CFSTR(", locked"));
-       }
        if (storePrivate->disconnectFunction != NULL) {
                CFStringAppendFormat(result, NULL, CFSTR(", disconnect = %p"), storePrivate->disconnectFunction);
        }
@@ -96,19 +94,21 @@ __SCDynamicStoreCopyDescription(CFTypeRef cf) {
                        CFStringAppendFormat(result, NULL, CFSTR(", BSD signal notifications"));
                        break;
                case Using_NotifierInformViaRunLoop :
-               case Using_NotifierInformViaCallback :
+               case Using_NotifierInformViaDispatch :
                        if (storePrivate->notifyStatus == Using_NotifierInformViaRunLoop) {
                                CFStringAppendFormat(result, NULL, CFSTR(", runloop notifications"));
                                CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->rlsFunction);
                                CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->rlsContext.info);
                                CFStringAppendFormat(result, NULL, CFSTR(", rls = %p"), storePrivate->rls);
-                       } else {
-                               CFStringAppendFormat(result, NULL, CFSTR(", mach port/callback notifications"));
-                               CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->callbackFunction);
-                               CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->callbackArgument);
+                       } else if (storePrivate->notifyStatus == Using_NotifierInformViaDispatch) {
+                               CFStringAppendFormat(result, NULL, CFSTR(", dispatch notifications"));
+                               CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->rlsFunction);
+                               CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->rlsContext.info);
+                               CFStringAppendFormat(result, NULL, CFSTR(", queue = %p"), storePrivate->dispatchQueue);
+                               CFStringAppendFormat(result, NULL, CFSTR(", source = %p"), storePrivate->dispatchSource);
                        }
-                       if (storePrivate->callbackRLS != NULL) {
-                               CFStringAppendFormat(result, NULL, CFSTR(", notify rls = %@" ), storePrivate->callbackRLS);
+                       if (storePrivate->rlsNotifyRLS != NULL) {
+                               CFStringAppendFormat(result, NULL, CFSTR(", notify rls = %@" ), storePrivate->rlsNotifyRLS);
                        }
                        CFStringAppendFormat(result, NULL, CFSTR("}"));
                        break;
@@ -127,7 +127,6 @@ static void
 __SCDynamicStoreDeallocate(CFTypeRef cf)
 {
        int                             oldThreadState;
-       int                             sc_status;
        SCDynamicStoreRef               store           = (SCDynamicStoreRef)cf;
        SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
 
@@ -136,24 +135,16 @@ __SCDynamicStoreDeallocate(CFTypeRef cf)
        /* Remove/cancel any outstanding notification requests. */
        (void) SCDynamicStoreNotifyCancel(store);
 
-       if ((storePrivate->server != MACH_PORT_NULL) && storePrivate->locked) {
-               (void) SCDynamicStoreUnlock(store);     /* release the lock */
-       }
-
        if (storePrivate->server != MACH_PORT_NULL) {
-               __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate", storePrivate->server);
-               (void) configclose(storePrivate->server, (int *)&sc_status);
-               __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate (after configclose)", storePrivate->server);
+               if (!storePrivate->serverNullSession) {
+                       /*
+                        * Remove our send right to the SCDynamicStore server (and that will
+                        * result in our session being closed).
+                        */
+                       __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate", storePrivate->server);
+                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
+               }
 
-               /*
-                * the above call to configclose() should result in the SCDynamicStore
-                * server code deallocating it's receive right.  That, in turn, should
-                * result in our send becoming a dead name.  We could explicitly remove
-                * the dead name right with a call to mach_port_mod_refs() but, to be
-                * sure, we use mach_port_deallocate() since that will get rid of a
-                * send, send_once, or dead name right.
-                */
-               (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
                storePrivate->server = MACH_PORT_NULL;
        }
 
@@ -313,14 +304,14 @@ __SCDynamicStoreCreatePrivate(CFAllocatorRef              allocator,
        }
 
        /* client side of the "configd" session */
-       storePrivate->name                              = NULL;
+       storePrivate->name                              = (name != NULL) ? CFRetain(name) : NULL;
        storePrivate->options                           = NULL;
 
        /* server side of the "configd" session */
        storePrivate->server                            = MACH_PORT_NULL;
+       storePrivate->serverNullSession                 = FALSE;
 
        /* flags */
-       storePrivate->locked                            = FALSE;
        storePrivate->useSessionKeys                    = FALSE;
 
        /* Notification status */
@@ -340,17 +331,13 @@ __SCDynamicStoreCreatePrivate(CFAllocatorRef              allocator,
                        storePrivate->rlsContext.info = (void *)(*context->retain)(context->info);
                }
        }
-
-       /* "client" information associated with SCDynamicStoreNotifyCallback() */
-       storePrivate->callbackFunction                  = NULL;
-       storePrivate->callbackArgument                  = NULL;
-       storePrivate->callbackPort                      = NULL;
-       storePrivate->callbackRLS                       = NULL;
+       storePrivate->rlsNotifyPort                     = NULL;
+       storePrivate->rlsNotifyRLS                      = NULL;
 
        /* "client" information associated with SCDynamicStoreSetDispatchQueue() */
+       storePrivate->dispatchGroup                     = NULL;
        storePrivate->dispatchQueue                     = NULL;
-       storePrivate->callbackSource                    = NULL;
-       storePrivate->callbackQueue                     = NULL;
+       storePrivate->dispatchSource                    = NULL;
 
        /* "client" information associated with SCDynamicStoreSetDisconnectCallBack() */
        storePrivate->disconnectFunction                = NULL;
@@ -379,15 +366,15 @@ __SCDynamicStoreCreatePrivate(CFAllocatorRef              allocator,
 static Boolean
 __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate)
 {
-       CFDataRef       myName;                 /* serialized name */
-       xmlData_t       myNameRef;
-       CFIndex         myNameLen;
-       CFDataRef       myOptions       = NULL; /* serialized options */
-       xmlData_t       myOptionsRef    = NULL;
-       CFIndex         myOptionsLen    = 0;
-       int             sc_status       = kSCStatusFailed;
-       mach_port_t     server;
-       kern_return_t   status          = KERN_SUCCESS;
+       CFDataRef               myName;                 /* serialized name */
+       xmlData_t               myNameRef;
+       CFIndex                 myNameLen;
+       CFDataRef               myOptions       = NULL; /* serialized options */
+       xmlData_t               myOptionsRef    = NULL;
+       CFIndex                 myOptionsLen    = 0;
+       int                     sc_status       = kSCStatusFailed;
+       mach_port_t             server;
+       kern_return_t           status          = KERN_SUCCESS;
 
        if (!_SCSerializeString(storePrivate->name, &myName, (void **)&myNameRef, &myNameLen)) {
                goto done;
@@ -405,13 +392,29 @@ __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate)
        server = _sc_server;
        while (TRUE) {
                if (server != MACH_PORT_NULL) {
-                       status = configopen(server,
-                                           myNameRef,
-                                           myNameLen,
-                                           myOptionsRef,
-                                           myOptionsLen,
-                                           &storePrivate->server,
-                                           (int *)&sc_status);
+                       if (!storePrivate->serverNullSession) {
+                               // if SCDynamicStore session
+                               status = configopen(server,
+                                                   myNameRef,
+                                                   myNameLen,
+                                                   myOptionsRef,
+                                                   myOptionsLen,
+                                                   &storePrivate->server,
+                                                   (int *)&sc_status);
+                       } else {
+                               // if NULL session
+                               if (storePrivate->server == MACH_PORT_NULL) {
+                                       // use the [main] SCDynamicStore server port
+                                       storePrivate->server = server;
+                                       sc_status = kSCStatusOK;
+                                       status = KERN_SUCCESS;
+                               } else {
+                                       // if the server port we used returned an error
+                                       storePrivate->server = MACH_PORT_NULL;
+                                       status = MACH_SEND_INVALID_DEST;
+                               }
+                       }
+
                        if (status == KERN_SUCCESS) {
                                break;
                        }
@@ -427,8 +430,11 @@ __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate)
                pthread_mutex_lock(&_sc_lock);
                if (_sc_server != MACH_PORT_NULL) {
                        if (server == _sc_server) {
-                               // if the server we tried returned the error
+                               // if the server we tried returned the error, deallocate
+                               // our send [or dead name] right
                                (void)mach_port_deallocate(mach_task_self(), _sc_server);
+
+                               // and [re-]lookup the name to the server
                                _sc_server = __SCDynamicStoreServerPort(&sc_status);
                        } else {
                                // another thread has refreshed the SCDynamicStore server port
@@ -459,11 +465,12 @@ __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate)
                        SCLog(TRUE,
                              (status == KERN_SUCCESS) ? LOG_DEBUG : LOG_ERR,
                              CFSTR("SCDynamicStore server not available"));
+                       sc_status = kSCStatusNoStoreServer;
                        break;
                default :
                        SCLog(TRUE,
                              (status == KERN_SUCCESS) ? LOG_DEBUG : LOG_ERR,
-                             CFSTR("SCDynamicStoreCreateAddSession configopen(): %s"),
+                             CFSTR("SCDynamicStoreAddSession configopen(): %s"),
                              SCErrorString(sc_status));
                        break;
        }
@@ -474,7 +481,52 @@ __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate)
 
 
 __private_extern__
-Boolean
+SCDynamicStoreRef
+__SCDynamicStoreNullSession(void)
+{
+       SCDynamicStorePrivateRef        storePrivate;
+       Boolean                         ok      = TRUE;
+       __SCThreadSpecificDataRef       tsd;
+
+       tsd = __SCGetThreadSpecificData();
+       if (tsd->_sc_store == NULL) {
+#if    !TARGET_IPHONE_SIMULATOR
+               storePrivate = __SCDynamicStoreCreatePrivate(NULL,
+                                                            CFSTR("NULL session"),
+                                                            NULL,
+                                                            NULL);
+               storePrivate->server = _sc_server;
+               storePrivate->serverNullSession = TRUE;
+#else
+               /*
+                * In the simulator, this code may be talking to an older version of
+                * configd that still requires a valid session. Instead of using a
+                * "NULL" session that uses the server mach port, set up a "normal"
+                * session in thread-local storage.
+                */
+               storePrivate = __SCDynamicStoreCreatePrivate(NULL,
+                                                            CFSTR("Thread local session"),
+                                                            NULL,
+                                                            NULL);
+               /*
+                * Use MACH_PORT_NULL here to trigger the call to
+                * __SCDynamicStoreAddSession below.
+                */
+               storePrivate->server = MACH_PORT_NULL;
+#endif /* TARGET_IPHONE_SIMULATOR */
+               tsd->_sc_store = (SCDynamicStoreRef)storePrivate;
+       }
+
+       storePrivate = (SCDynamicStorePrivateRef)tsd->_sc_store;
+       if (storePrivate->server == MACH_PORT_NULL) {
+               ok = __SCDynamicStoreAddSession(storePrivate);
+       }
+
+       return ok ? tsd->_sc_store : NULL;
+}
+
+
+static Boolean
 __SCDynamicStoreReconnect(SCDynamicStoreRef store)
 {
        Boolean                         ok;
@@ -485,6 +537,47 @@ __SCDynamicStoreReconnect(SCDynamicStoreRef store)
 }
 
 
+__private_extern__
+Boolean
+__SCDynamicStoreCheckRetryAndHandleError(SCDynamicStoreRef     store,
+                                        kern_return_t          status,
+                                        int                    *sc_status,
+                                        const char             *log_str)
+{
+       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
+
+       if (status == KERN_SUCCESS) {
+               /* no error */
+               return FALSE;
+       }
+
+       if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
+               /* the server's gone */
+               if (!storePrivate->serverNullSession) {
+                       /*
+                        * remove the session's dead name right (and not the
+                        * not the "server" port)
+                        */
+                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
+               }
+               storePrivate->server = MACH_PORT_NULL;
+
+               /* reconnect */
+               if (__SCDynamicStoreReconnect(store)) {
+                       /* retry needed */
+                       return TRUE;
+               }
+       } else {
+               /* an unexpected error, leave the [session] port alone */
+               SCLog(TRUE, LOG_ERR, CFSTR("%s: %s"), log_str, mach_error_string(status));
+               storePrivate->server = MACH_PORT_NULL;
+       }
+
+       *sc_status = status;
+       return FALSE;
+}
+
+
 static void
 pushDisconnect(SCDynamicStoreRef store)
 {
@@ -545,25 +638,13 @@ __SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store)
                        break;
        }
 
-#ifdef NOTNOW
-       // invalidate the run loop source(s)
-       if (storePrivate->callbackRLS != NULL) {
-               CFRunLoopSourceInvalidate(storePrivate->callbackRLS);
-               CFRelease(storePrivate->callbackRLS);
-               storePrivate->callbackRLS = NULL;
-       }
-
-       // invalidate port
-       if (storePrivate->callbackPort != NULL) {
-               __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreReconnectNotifications w/MACH_NOTIFY_NO_SENDERS", CFMachPortGetPort(storePrivate->callbackPort));
-               CFMachPortInvalidate(storePrivate->callbackPort);
-               CFRelease(storePrivate->callbackPort);
-               storePrivate->callbackPort = NULL;
-       }
-#endif // NOTNOW
-
        // cancel [old] notifications
-       SCDynamicStoreNotifyCancel(store);
+       if (!SCDynamicStoreNotifyCancel(store)) {
+               // if we could not cancel / reconnect
+               SCLog(TRUE, LOG_DEBUG,
+                     CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreNotifyCancel() failed: %s"),
+                     SCErrorString(SCError()));
+       }
 
        // set notification keys & patterns
        if ((storePrivate->keys != NULL) || (storePrivate->patterns)) {
@@ -662,7 +743,7 @@ SCDynamicStoreCreateWithOptions(CFAllocatorRef              allocator,
        SCDynamicStorePrivateRef        storePrivate;
 
        // allocate and initialize a new session
-       storePrivate = __SCDynamicStoreCreatePrivate(allocator, name, callout, context);
+       storePrivate = __SCDynamicStoreCreatePrivate(allocator, NULL, callout, context);
        if (storePrivate == NULL) {
                return NULL;
        }
index 5a1bf29ec0561dda26ec846dc524691982fa344d..0f3e346debc02b366815683f6a43a8d93d972dd8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -52,7 +52,6 @@
 #include <pthread.h>
 
 #include <execinfo.h>
-#include <libproc.h>
 #include <unistd.h>
 #include <dlfcn.h>
 
@@ -129,38 +128,47 @@ _SC_cfstring_to_cstring(CFStringRef cfstr, char *buf, CFIndex bufLen, CFStringEn
 void
 _SC_sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen)
 {
+       union {
+               const struct sockaddr           *sa;
+               const struct sockaddr_in        *sin;
+               const struct sockaddr_in6       *sin6;
+               const struct sockaddr_dl        *sdl;
+       } addr;
+
+       addr.sa = address;
+
        bzero(buf, bufLen);
        switch (address->sa_family) {
                case AF_INET :
-                       (void)inet_ntop(((struct sockaddr_in *)address)->sin_family,
-                                       &((struct sockaddr_in *)address)->sin_addr,
+                       (void)inet_ntop(addr.sin->sin_family,
+                                       &addr.sin->sin_addr,
                                        buf,
                                        bufLen);
                        break;
                case AF_INET6 : {
-                       (void)inet_ntop(((struct sockaddr_in6 *)address)->sin6_family,
-                                       &((struct sockaddr_in6 *)address)->sin6_addr,
+                       (void)inet_ntop(addr.sin6->sin6_family,
+                                       &addr.sin6->sin6_addr,
                                        buf,
                                        bufLen);
-                       if (((struct sockaddr_in6 *)address)->sin6_scope_id != 0) {
+                       if (addr.sin6->sin6_scope_id != 0) {
                                int     n;
 
                                n = strlen(buf);
                                if ((n+IF_NAMESIZE+1) <= (int)bufLen) {
                                        buf[n++] = '%';
-                                       if_indextoname(((struct sockaddr_in6 *)address)->sin6_scope_id, &buf[n]);
+                                       if_indextoname(addr.sin6->sin6_scope_id, &buf[n]);
                                }
                        }
                        break;
                }
                case AF_LINK :
-                       if (((struct sockaddr_dl *)address)->sdl_len < bufLen) {
-                               bufLen = ((struct sockaddr_dl *)address)->sdl_len;
+                       if (addr.sdl->sdl_len < bufLen) {
+                               bufLen = addr.sdl->sdl_len;
                        } else {
                                bufLen = bufLen - 1;
                        }
 
-                       bcopy(((struct sockaddr_dl *)address)->sdl_data, buf, bufLen);
+                       bcopy(addr.sdl->sdl_data, buf, bufLen);
                        break;
                default :
                        snprintf(buf, bufLen, "unexpected address family %d", address->sa_family);
@@ -171,6 +179,66 @@ _SC_sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen)
 }
 
 
+struct sockaddr *
+_SC_string_to_sockaddr(const char *str, sa_family_t af, void *buf, size_t bufLen)
+{
+       union {
+               void                    *buf;
+               struct sockaddr         *sa;
+               struct sockaddr_in      *sin;
+               struct sockaddr_in6     *sin6;
+       } addr;
+
+       if (buf == NULL) {
+               bufLen = sizeof(struct sockaddr_storage);
+               addr.buf = CFAllocatorAllocate(NULL, bufLen, 0);
+       } else {
+               addr.buf = buf;
+       }
+
+       bzero(addr.buf, bufLen);
+       if (((af == AF_UNSPEC) || (af == AF_INET)) &&
+           (bufLen >= sizeof(struct sockaddr_in)) &&
+           inet_aton(str, &addr.sin->sin_addr) == 1) {
+               // if IPv4 address
+               addr.sin->sin_len    = sizeof(struct sockaddr_in);
+               addr.sin->sin_family = AF_INET;
+       } else if (((af == AF_UNSPEC) || (af == AF_INET6)) &&
+                  (bufLen >= sizeof(struct sockaddr_in6)) &&
+                  inet_pton(AF_INET6, str, &addr.sin6->sin6_addr) == 1) {
+               // if IPv6 address
+               char    *p;
+
+               addr.sin6->sin6_len    = sizeof(struct sockaddr_in6);
+               addr.sin6->sin6_family = AF_INET6;
+
+               p = strchr(buf, '%');
+               if (p != NULL) {
+                       addr.sin6->sin6_scope_id = if_nametoindex(p + 1);
+               }
+
+               if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6->sin6_addr) ||
+                   IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6->sin6_addr)) {
+                       uint16_t        if_index;
+
+                       if_index = ntohs(addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1]);
+                       addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
+                       if (addr.sin6->sin6_scope_id == 0) {
+                               // use the scope id that was embedded in the [link local] IPv6 address
+                               addr.sin6->sin6_scope_id = if_index;
+                       }
+               }
+       } else {
+               if (addr.buf != buf) {
+                       CFAllocatorDeallocate(NULL, addr.buf);
+               }
+               addr.buf = NULL;
+       }
+
+       return addr.sa;
+}
+
+
 void
 _SC_sendMachMessage(mach_port_t port, mach_msg_id_t msg_id)
 {
@@ -305,7 +373,7 @@ _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dat
 Boolean
 _SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dataLen)
 {
-       CFErrorRef      error;
+       CFErrorRef      error   = NULL;
 
        if (xml == NULL) {
                kern_return_t   status;
@@ -471,7 +539,7 @@ _SCUnserializeData(CFDataRef *data, void *dataRef, CFIndex dataLen)
 }
 
 
-CFDictionaryRef
+CF_RETURNS_RETAINED CFDictionaryRef
 _SCSerializeMultiple(CFDictionaryRef dict)
 {
        const void *            keys_q[N_QUICK];
@@ -529,6 +597,7 @@ _SCSerializeMultiple(CFDictionaryRef dict)
 }
 
 
+CF_RETURNS_RETAINED
 CFDictionaryRef
 _SCUnserializeMultiple(CFDictionaryRef dict)
 {
@@ -821,48 +890,92 @@ _SC_CFBundleGet(void)
 CFStringRef
 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName)
 {
+       CFDataRef       data    = NULL;
+       SInt32          errCode = 0;
+       CFURLRef        resourcesURL;
        CFStringRef     str     = NULL;
        CFURLRef        url;
 
        if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) tableName = CFSTR("Localizable");
 
-       url = CFBundleCopyResourceURLForLocalization(bundle,
-                                                    tableName,
-                                                    CFSTR("strings"),
-                                                    NULL,
-                                                    CFSTR("English"));
-       if (url != NULL) {
-               CFDataRef       data    = NULL;
-               SInt32          errCode = 0;
-
-               if (CFURLCreateDataAndPropertiesFromResource(NULL,
-                                                            url,
-                                                            &data,
-                                                            NULL,
-                                                            NULL,
-                                                            &errCode)) {
-                       CFDictionaryRef table;
+       /*
+        * First, try getting the requested string using a manually constructed
+        * URL to <bundle>/Resources/English.lproj/<tableName>.strings. Do this
+        * because CFBundleCopyResourceURLForLocalization() uses CFPreferences
+        * to get the preferred localizations, CFPreferences talks to
+        * OpenDirectory, and OpenDirectory tries to obtain the platform UUID.
+        * On machines where the platform UUID is set by InterfaceNamer, a
+        * deadlock can occur if InterfaceNamer calls
+        * CFBundleCopyResourceURLForLocalization() before setting the
+        * platform UUID in the kernel.
+        */
+       resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
+       if (resourcesURL != NULL) {
+               CFStringRef fileName = CFStringCreateWithFormat(
+                                           NULL, NULL, CFSTR("%@.strings"), tableName);
+               CFURLRef enlproj = CFURLCreateCopyAppendingPathComponent(
+                                     NULL, resourcesURL, CFSTR("English.lproj"), true);
+               url = CFURLCreateCopyAppendingPathComponent(
+                                  NULL, enlproj, fileName, false);
+               CFRelease(enlproj);
+               CFRelease(fileName);
+               CFRelease(resourcesURL);
+
+               if (!CFURLCreateDataAndPropertiesFromResource(NULL,
+                                                             url,
+                                                             &data,
+                                                             NULL,
+                                                             NULL,
+                                                             &errCode)) {
+                       /*
+                        * Failed to get the data using a manually-constructed URL
+                        * for the given strings table. Fall back to using
+                        * CFBundleCopyResourceURLForLocalization() below.
+                        */
+                       data = NULL;
+               }
+               CFRelease(url);
+       }
 
-                       table = CFPropertyListCreateWithData(NULL,
-                                                            data,
-                                                            kCFPropertyListImmutable,
+       if (data == NULL) {
+               url = CFBundleCopyResourceURLForLocalization(bundle,
+                                                            tableName,
+                                                            CFSTR("strings"),
                                                             NULL,
-                                                            NULL);
-                       if (table != NULL) {
-                               if (isA_CFDictionary(table)) {
-                                       str = CFDictionaryGetValue(table, key);
-                                       if (str != NULL) {
-                                               CFRetain(str);
-                                       }
-                               }
+                                                            CFSTR("English"));
+               if (url != NULL) {
+                       if (!CFURLCreateDataAndPropertiesFromResource(NULL,
+                                                                     url,
+                                                                     &data,
+                                                                     NULL,
+                                                                     NULL,
+                                                                     &errCode)) {
+                               data = NULL;
+                       }
+                       CFRelease(url);
+               }
+       }
 
-                               CFRelease(table);
+       if (data != NULL) {
+               CFDictionaryRef table;
+
+               table = CFPropertyListCreateWithData(NULL,
+                                                    data,
+                                                    kCFPropertyListImmutable,
+                                                    NULL,
+                                                    NULL);
+               if (table != NULL) {
+                       if (isA_CFDictionary(table)) {
+                               str = CFDictionaryGetValue(table, key);
+                               if (str != NULL) {
+                                       CFRetain(str);
+                               }
                        }
 
-                       CFRelease(data);
+                       CFRelease(table);
                }
 
-               CFRelease(url);
+               CFRelease(data);
        }
 
        if (str == NULL) {
@@ -879,9 +992,9 @@ _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFString
 
 CFMachPortRef
 _SC_CFMachPortCreateWithPort(const char                *portDescription,
-                                mach_port_t            portNum,
-                                CFMachPortCallBack     callout,
-                                CFMachPortContext      *context)
+                            mach_port_t        portNum,
+                            CFMachPortCallBack callout,
+                            CFMachPortContext  *context)
 {
        CFMachPortRef   port;
        Boolean shouldFree      = FALSE;
@@ -890,7 +1003,6 @@ _SC_CFMachPortCreateWithPort(const char            *portDescription,
        if ((port == NULL) || shouldFree) {
                CFStringRef     err;
                char            *crash_info     = NULL;
-               char            name[64]        = "";
 
                SCLog(TRUE, LOG_ERR,
                      CFSTR("%s: CFMachPortCreateWithPort() failed , port = %p"),
@@ -908,11 +1020,10 @@ _SC_CFMachPortCreateWithPort(const char          *portDescription,
                crash_info = _SC_cfstring_to_cstring(err, NULL, 0, kCFStringEncodingASCII);
                CFRelease(err);
 
-               (void) proc_name(getpid(), name, sizeof(name));
                err = CFStringCreateWithFormat(NULL,
                                               NULL,
                                               CFSTR("A recycled mach_port has been detected by \"%s\"."),
-                                              name);
+                                              getprogname());
                _SC_crash(crash_info, CFSTR("CFMachPort error"), err);
                CFAllocatorDeallocate(NULL, crash_info);
                CFRelease(err);
@@ -1086,10 +1197,7 @@ _SC_logMachPortReferences(const char *str, mach_port_t port)
                static int      is_configd      = -1;
 
                if (is_configd == -1) {
-                       char    name[64]        = "";
-
-                       (void) proc_name(getpid(), name, sizeof(name));
-                       is_configd = (strncmp(name, "configd", sizeof(name)) == 0);
+                       is_configd = (strcmp(getprogname(), "configd") == 0);
                }
                if (is_configd == 1) {
                        // if "configd", add indication if this is the M[ain] or [P]lugin thread
@@ -1111,20 +1219,22 @@ _SC_logMachPortReferences(const char *str, mach_port_t port)
        status = mach_port_type(mach_task_self(), port, &pt);
        if (status != KERN_SUCCESS) {
                SCLog(TRUE, LOG_NOTICE,
-                     CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND): %s"),
+                     CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s"),
                      buf,
                      port,
                      mach_error_string(status));
+               return;
        }
 
        if ((pt & MACH_PORT_TYPE_SEND) != 0) {
                status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND,      &refs_send);
                if (status != KERN_SUCCESS) {
                        SCLog(TRUE, LOG_NOTICE,
-                             CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND): %s"),
+                             CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s"),
                              buf,
                              port,
                              mach_error_string(status));
+                       return;
                }
        }
 
@@ -1134,10 +1244,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port)
                status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE,   &refs_recv);
                if (status != KERN_SUCCESS) {
                        SCLog(TRUE, LOG_NOTICE,
-                             CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_RECEIVE): %s"),
+                             CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_RECEIVE): %s"),
                              buf,
                              port,
                              mach_error_string(status));
+                       return;
                }
 
                count = MACH_PORT_RECEIVE_STATUS_COUNT;
@@ -1148,10 +1259,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port)
                                               &count);
                if (status != KERN_SUCCESS) {
                        SCLog(TRUE, LOG_NOTICE,
-                             CFSTR("%mach_port_get_attributes(..., %d, MACH_PORT_RECEIVE_STATUS): %s"),
+                             CFSTR("%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s"),
                              buf,
                              port,
                              mach_error_string(status));
+                       return;
                }
        }
 
@@ -1159,10 +1271,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port)
                status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, &refs_once);
                if (status != KERN_SUCCESS) {
                        SCLog(TRUE, LOG_NOTICE,
-                             CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND_ONCE): %s"),
+                             CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND_ONCE): %s"),
                              buf,
                              port,
                              mach_error_string(status));
+                       return;
                }
        }
 
@@ -1170,10 +1283,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port)
                status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET,  &refs_pset);
                if (status != KERN_SUCCESS) {
                        SCLog(TRUE, LOG_NOTICE,
-                             CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_PORT_SET): %s"),
+                             CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_PORT_SET): %s"),
                              buf,
                              port,
                              mach_error_string(status));
+                       return;
                }
        }
 
@@ -1181,10 +1295,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port)
                status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, &refs_dead);
                if (status != KERN_SUCCESS) {
                        SCLog(TRUE, LOG_NOTICE,
-                             CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_DEAD_NAME): %s"),
+                             CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_DEAD_NAME): %s"),
                              buf,
                              port,
                              mach_error_string(status));
+                       return;
                }
        }
 
@@ -1244,16 +1359,14 @@ asm(".desc ___crashreporter_info__, 0x10");
 static Boolean
 _SC_SimulateCrash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
 {
+       Boolean ok                                                                                      = FALSE;
+
+#if ! TARGET_IPHONE_SIMULATOR
        static bool     (*dyfunc_SimulateCrash)(pid_t, mach_exception_data_type_t, CFStringRef) = NULL;
        static void     *image                                                                                  = NULL;
-       Boolean ok                                                                                      = FALSE;
 
        if ((dyfunc_SimulateCrash == NULL) && (image == NULL)) {
-               const char      *framework      = "/System/Library/PrivateFrameworks/CrashReporterSupport.framework/"
-#if    !TARGET_OS_EMBEDDED
-                                                       "Versions/A/"
-#endif // !TARGET_OS_EMBEDDED
-                                                       "CrashReporterSupport";
+               const char      *framework      = "/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport";
                struct stat     statbuf;
                const char      *suffix = getenv("DYLD_IMAGE_SUFFIX");
                char            path[MAXPATHLEN];
@@ -1303,6 +1416,7 @@ _SC_SimulateCrash(const char *crash_info, CFStringRef notifyHeader, CFStringRef
                }
        }
 #endif // TARGET_OS_EMBEDDED && !TARGET_OS_EMBEDDED_OTHER && !defined(DO_NOT_INFORM)
+#endif /* ! TARGET_IPHONE_SIMULATOR */
 
        return ok;
 }
index 5f1230dccb854bd02db8f526a56dc9e8d7f6b7bd..38fc2ffd9458e94a9bb6710dce8f52984ff7dc15 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -42,7 +42,7 @@
 Boolean
 SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        CFDataRef                       utfKey;         /* serialized key */
        xmlData_t                       myKeyRef;
@@ -50,11 +50,15 @@ SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
        int                             sc_status;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return FALSE;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                /* sorry, you must have an open session to play */
                _SCErrorSet(kSCStatusNoStoreServer);
@@ -75,21 +79,11 @@ SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
                              myKeyLen,
                              (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreRemoveValue configremove(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreRemoveValue configremove()")) {
+               goto retry;
        }
 
        /* clean up */
index a0b2221714304f11d4fb0229d7392799209cd1fb..81afaf40d63342c801a1ae597c4737f72d8b1f02 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2006, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2006, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -46,7 +46,7 @@ SCDynamicStoreSetMultiple(SCDynamicStoreRef   store,
                          CFArrayRef            keysToRemove,
                          CFArrayRef            keysToNotify)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        CFDataRef                       xmlSet          = NULL; /* key/value pairs to set (XML serialized) */
        xmlData_t                       mySetRef        = NULL; /* key/value pairs to set (serialized) */
@@ -60,11 +60,15 @@ SCDynamicStoreSetMultiple(SCDynamicStoreRef store,
        int                             sc_status;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return FALSE;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                _SCErrorSet(kSCStatusNoStoreServer);
                return FALSE;   /* you must have an open session to play */
@@ -120,21 +124,11 @@ SCDynamicStoreSetMultiple(SCDynamicStoreRef       store,
                             myNotifyLen,
                             (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetMultiple configset_m(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreSetMultiple configset_m()")) {
+               goto retry;
        }
 
        /* clean up */
@@ -153,7 +147,7 @@ SCDynamicStoreSetMultiple(SCDynamicStoreRef store,
 Boolean
 SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        CFDataRef                       utfKey;         /* serialized key */
        xmlData_t                       myKeyRef;
@@ -165,11 +159,15 @@ SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListR
        int                             newInstance;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return FALSE;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                /* sorry, you must have an open session to play */
                _SCErrorSet(kSCStatusNoStoreServer);
@@ -201,21 +199,11 @@ SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListR
                           &newInstance,
                           (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetValue configset(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreSetValue configset()")) {
+               goto retry;
        }
 
        /* clean up */
index 42277908c510759345cd0a740a46f21154c25ecb..3c8ac059ebfb9ed92fbea8fb63c9c2365f3dc794 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004, 2005, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 Boolean
 SCDynamicStoreSnapshot(SCDynamicStoreRef store)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
+       SCDynamicStorePrivateRef        storePrivate;
        kern_return_t                   status;
        int                             sc_status;
 
        if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
+               store = __SCDynamicStoreNullSession();
+               if (store == NULL) {
+                       /* sorry, you must provide a session */
+                       _SCErrorSet(kSCStatusNoStoreSession);
+                       return FALSE;
+               }
        }
 
+       storePrivate = (SCDynamicStorePrivateRef)store;
        if (storePrivate->server == MACH_PORT_NULL) {
                /* sorry, you must have an open session to play */
                _SCErrorSet(kSCStatusNoStoreServer);
@@ -62,21 +66,11 @@ SCDynamicStoreSnapshot(SCDynamicStoreRef store)
 
        status = snapshot(storePrivate->server, (int *)&sc_status);
 
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSnapshot snapshot(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
+       if (__SCDynamicStoreCheckRetryAndHandleError(store,
+                                                    status,
+                                                    &sc_status,
+                                                    "SCDynamicStoreSnapshot snapshot()")) {
+               goto retry;
        }
 
        if (sc_status != kSCStatusOK) {
diff --git a/SystemConfiguration.fproj/SCDTouch.c b/SystemConfiguration.fproj/SCDTouch.c
deleted file mode 100644 (file)
index ca7ea4e..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * Modification History
- *
- * June 1, 2001                        Allan Nathanson <ajn@apple.com>
- * - public API conversion
- *
- * June 20, 2000               Allan Nathanson <ajn@apple.com>
- * - initial revision
- */
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCPrivate.h>
-#include "SCDynamicStoreInternal.h"
-#include "config.h"            /* MiG generated file */
-
-Boolean
-SCDynamicStoreTouchValue(SCDynamicStoreRef store, CFStringRef key)
-{
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-       kern_return_t                   status;
-       CFDataRef                       utfKey;         /* serialized key */
-       xmlData_t                       myKeyRef;
-       CFIndex                         myKeyLen;
-       int                             sc_status;
-
-       if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
-       }
-
-       if (storePrivate->server == MACH_PORT_NULL) {
-               /* sorry, you must have an open session to play */
-               _SCErrorSet(kSCStatusNoStoreServer);
-               return FALSE;
-       }
-
-       /* serialize the key */
-       if (!_SCSerializeString(key, &utfKey, (void **)&myKeyRef, &myKeyLen)) {
-               _SCErrorSet(kSCStatusFailed);
-               return FALSE;
-       }
-
-    retry :
-
-       /* send the key to the server */
-       status = configtouch(storePrivate->server,
-                            myKeyRef,
-                            myKeyLen,
-                            (int *)&sc_status);
-
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreTouchValue configtouch(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       if (__SCDynamicStoreReconnect(store)) {
-                               goto retry;
-                       }
-               }
-               sc_status = status;
-       }
-
-       /* clean up */
-       CFRelease(utfKey);
-
-       if (sc_status != kSCStatusOK) {
-               _SCErrorSet(sc_status);
-               return FALSE;
-       }
-
-       return TRUE;
-}
diff --git a/SystemConfiguration.fproj/SCDUnlock.c b/SystemConfiguration.fproj/SCDUnlock.c
deleted file mode 100644 (file)
index 06ac770..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * Modification History
- *
- * June 1, 2001                        Allan Nathanson <ajn@apple.com>
- * - public API conversion
- *
- * March 24, 2000              Allan Nathanson <ajn@apple.com>
- * - initial revision
- */
-
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCPrivate.h>
-#include "SCDynamicStoreInternal.h"
-#include "config.h"            /* MiG generated file */
-
-Boolean
-SCDynamicStoreUnlock(SCDynamicStoreRef store)
-{
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-       kern_return_t                   status;
-       int                             sc_status;
-
-       if (store == NULL) {
-               /* sorry, you must provide a session */
-               _SCErrorSet(kSCStatusNoStoreSession);
-               return FALSE;
-       }
-
-       if (storePrivate->server == MACH_PORT_NULL) {
-               /* sorry, you must have an open session to play */
-               _SCErrorSet(kSCStatusNoStoreServer);
-               return FALSE;
-       }
-
-       /* (attempt to) release the servers lock */
-       status = configunlock(storePrivate->server, (int *)&sc_status);
-       if (status != KERN_SUCCESS) {
-               if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
-                       /* the server's gone and our session port's dead, remove the dead name right */
-                       (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
-               } else {
-                       /* we got an unexpected error, leave the [session] port alone */
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreUnlock configunlock(): %s"), mach_error_string(status));
-               }
-               storePrivate->server = MACH_PORT_NULL;
-               if (((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED))
-                   && __SCDynamicStoreReconnect(store)) {
-                       sc_status = kSCStatusOK;
-               } else {
-                       sc_status = status;
-               }
-       }
-
-       if (sc_status != kSCStatusOK) {
-               _SCErrorSet(sc_status);
-               return FALSE;
-       }
-
-       return TRUE;
-}
index db0590ad67132cd651df26326c306c7d8eefdb69..7682d42d41f6078bfa3d4d4e39e6eeebfe03364b 100644 (file)
@@ -95,6 +95,23 @@ DHCPInfoGetOptionData                (CFDictionaryRef        info,
 CFDateRef
 DHCPInfoGetLeaseStartTime      (CFDictionaryRef        info)           __OSX_AVAILABLE_STARTING(__MAC_10_1,__IPHONE_2_0/*SPI*/);
 
+
+/*!
+       @function DHCPInfoGetLeaseExpirationTime
+       @discussion Returns a CFDateRef corresponding to the lease expiration time,
+               if present.
+       @param info The non-NULL DHCP information dictionary returned by
+               calling SCDynamicStoreCopyDHCPInfo.
+       @result Returns a non-NULL CFDateRef if the DHCP lease has an expiration;
+               NULL if the lease is infinite i.e. has no expiration, or the
+               configuration method is not DHCP. An infinite lease can be determined
+               by a non-NULL lease start time (see DHCPInfoGetLeaseStartTime above).
+        
+               The return value must NOT be released.
+*/
+CFDateRef
+DHCPInfoGetLeaseExpirationTime (CFDictionaryRef        info)           __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_NA);
+
 __END_DECLS
 
 #endif /* USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS */
index 04dc0ffbc3a2afaac1a9b159da5cafa8dafc2e17..a32aa7fe6794784de58d849da51e2855e2f59417 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -41,7 +41,6 @@
 typedef enum {
        NotifierNotRegistered = 0,
        Using_NotifierWait,
-       Using_NotifierInformViaCallback,
        Using_NotifierInformViaMachPort,
        Using_NotifierInformViaFD,
        Using_NotifierInformViaSignal,
@@ -61,9 +60,9 @@ typedef struct {
 
        /* server side of the "configd" session */
        mach_port_t                     server;
+       Boolean                         serverNullSession;
 
        /* per-session flags */
-       Boolean                         locked;
        Boolean                         useSessionKeys;
 
        /* current status of notification requests */
@@ -74,27 +73,23 @@ typedef struct {
        CFRunLoopSourceRef              rls;
        SCDynamicStoreCallBack          rlsFunction;
        SCDynamicStoreContext           rlsContext;
-
-       /* "client" information associated with SCDynamicStoreNotifyCallback() */
-       SCDynamicStoreCallBack_v1       callbackFunction;
-       void                            *callbackArgument;
-       CFMachPortRef                   callbackPort;
-       CFRunLoopSourceRef              callbackRLS;
+       CFMachPortRef                   rlsNotifyPort;
+       CFRunLoopSourceRef              rlsNotifyRLS;
 
        /* "client" information associated with SCDynamicStoreSetDispatchQueue() */
+       dispatch_group_t                dispatchGroup;
        dispatch_queue_t                dispatchQueue;
-       dispatch_source_t               callbackSource;
-       dispatch_queue_t                callbackQueue;
+       dispatch_source_t               dispatchSource;
 
        /* "client" information associated with SCDynamicStoreSetDisconnectCallBack() */
        SCDynamicStoreDisconnectCallBack        disconnectFunction;
        Boolean                                 disconnectForceCallBack;
 
-       /* "server" SCDynamicStoreKeys being watched */
+       /* SCDynamicStoreKeys being watched */
        CFMutableArrayRef               keys;
        CFMutableArrayRef               patterns;
 
-       /* "server" information associated with SCDynamicStoreNotifyMachPort() */
+       /* "server" information associated with mach port based notifications */
        mach_port_t                     notifyPort;
        mach_msg_id_t                   notifyPortIdentifier;
 
@@ -117,8 +112,14 @@ __SCDynamicStoreCreatePrivate              (CFAllocatorRef                 allocator,
                                         SCDynamicStoreCallBack         callout,
                                         SCDynamicStoreContext          *context);
 
+SCDynamicStoreRef
+__SCDynamicStoreNullSession            (void);
+
 Boolean
-__SCDynamicStoreReconnect              (SCDynamicStoreRef              store);
+__SCDynamicStoreCheckRetryAndHandleError(SCDynamicStoreRef             store,
+                                        kern_return_t                  status,
+                                        int                            *sc_status,
+                                        const char                     *func);
 
 Boolean
 __SCDynamicStoreReconnectNotifications (SCDynamicStoreRef              store);
index 1837b6ad6f65d8530e1f541e8c979961718cf093..af5a5cc1fd83d49b04391ed30317a4fbf3743d63 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2004, 2005, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004, 2005, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
                   not make multiple calls to SCDynamicStoreSetValue).
  */
 
-/*!
-       @typedef SCDynamicStoreCallBack
-       @discussion Type of the callback function used when a
-               dynamic store change is delivered.
-       @param store The "dynamic store" session.
-       @param info ....
- */
-typedef boolean_t (*SCDynamicStoreCallBack_v1) (
-                                               SCDynamicStoreRef       store,
-                                               void                    *info
-                                               );
-
 /*!
        @typedef SCDynamicStoreDisconnectCallBack
        @discussion Type of callback function used when notification of
@@ -123,45 +111,6 @@ typedef void (*SCDynamicStoreDisconnectCallBack)   (
 
 __BEGIN_DECLS
 
-/*!
-       @function SCDynamicStoreLock
-       @discussion Locks access to the configuration "dynamic store".  All
-               other clients attempting to access the "dynamic store" will
-               block. All change notifications will be deferred until the
-               lock is released.
-       @param store The "dynamic store" session that should be locked.
-       @result TRUE if the lock was obtained; FALSE if an error was encountered.
- */
-Boolean
-SCDynamicStoreLock                     (SCDynamicStoreRef              store);
-
-/*!
-       @function SCDynamicStoreUnlock
-       @discussion Unlocks access to the configuration "dynamic store".  Other
-               clients will be able to access the "dynamic store". Any change
-               notifications will be delivered.
-       @param store The "dynamic store" session that should be unlocked.
-       @result TRUE if the lock was released; FALSE if an error was encountered.
- */
-Boolean
-SCDynamicStoreUnlock                   (SCDynamicStoreRef              store);
-
-/*!
-       @function SCDynamicStoreTouchValue
-       @discussion Updates the value of the specified key in the
-               "dynamic store".
-               If the value does not exist then a CFDate object
-               will be associated with the key.
-               If the associated data is already a CFDate object
-               then it will be updated with the current time.
-       @param store The "dynamic store" session.
-       @param key The key of the value to updated.
-       @result TRUE if the value was updated; FALSE if an error was encountered.
- */
-Boolean
-SCDynamicStoreTouchValue               (SCDynamicStoreRef              store,
-                                        CFStringRef                    key);
-
 /*!
        @function SCDynamicStoreAddWatchedKey
        @discussion Adds the specified key to the list of "dynamic store"
@@ -196,61 +145,6 @@ SCDynamicStoreRemoveWatchedKey             (SCDynamicStoreRef              store,
                                         CFStringRef                    key,
                                         Boolean                        isRegex);
 
-/*!
-       @function SCDynamicStoreNotifyCallback
-       @discussion Requests that the specified function be called whenever a
-               change has been detected to one of the "dynamic store" values
-               being monitored.
-
-       The callback function will be called with two arguments, store and
-       context, that correspond to the current "dynamic store" session and
-       the provided context argument.
-
-       The callback function should return a Boolean value indicating
-       whether an error occurred during execution of the callback.
-
-       Note: An additional run loop source will be added for the notification.
-       This additional source will be removed if the notification is cancelled
-       or if the callback indicates that an error was detected.
-
-       @param store The "dynamic store" session.
-       @param runLoop A pointer to the run loop.
-       @param func The callback function to call for each notification.
-               If this parameter is not a pointer to a function of the
-               correct prototype, the behavior is undefined.
-       @param context A pointer-sized user-defined value, that is passed as
-               the second parameter to the notification callback function,
-               but is otherwise unused by this function.  If the context
-               is not what is expected by the notification function, the
-               behavior is undefined.
-       @result TRUE if the notification callback runloop source was
-               successfully added; FALSE if an error was encountered.
- */
-Boolean
-SCDynamicStoreNotifyCallback           (SCDynamicStoreRef              store,
-                                        CFRunLoopRef                   runLoop,
-                                        SCDynamicStoreCallBack_v1      func,
-                                        void                           *context);
-
-/*!
-       @function SCDynamicStoreNotifyMachPort
-       @discussion Allocates a mach port that can be used to detect changes to
-               one of the system configuration data entries associated with the
-               current session's notifier keys. When a change is detected, an
-               empty (no data) mach message with the specified identifier will
-               be delivered to the calling application via the allocated port.
-
-       @param store An SCDynamicStoreRef that should be used for communication with the server.
-       @param msgid A mach message ID to be included with any notifications.
-       @param port A pointer to a mach port.  Upon return, port will be filled
-               with the mach port that will be used for any notifications.
-       @result A boolean indicating the success (or failure) of the call.
- */
-Boolean
-SCDynamicStoreNotifyMachPort           (SCDynamicStoreRef              store,
-                                        mach_msg_id_t                  msgid,
-                                        mach_port_t                    *port);
-
 /*!
        @function SCDynamicStoreNotifyFileDescriptor
        @discussion Allocates a file descriptor that can be used to detect changes
index 06f71cdc1b8b10f3605ce8d0ceed3643b5d7a7fb..41449cdfedd5333f7f85a9914f158e3ae7a40496 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2004, 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2002, 2004, 2006, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -47,19 +47,6 @@ SCDynamicStoreCopyLocation(SCDynamicStoreRef store)
        CFDictionaryRef         dict            = NULL;
        CFStringRef             key;
        CFStringRef             location        = NULL;
-       Boolean                 tempSession     = FALSE;
-
-       if (store == NULL) {
-               store = SCDynamicStoreCreate(NULL,
-                                            CFSTR("SCDynamicStoreCopyLocation"),
-                                            NULL,
-                                            NULL);
-               if (store == NULL) {
-                       SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed"));
-                       return NULL;
-               }
-               tempSession = TRUE;
-       }
 
        key  = SCDynamicStoreKeyCreateLocation(NULL);
        dict = SCDynamicStoreCopyValue(store, key);
@@ -70,7 +57,8 @@ SCDynamicStoreCopyLocation(SCDynamicStoreRef store)
        }
 
        location = CFDictionaryGetValue(dict, kSCDynamicStorePropSetupCurrentSet);
-       if (!isA_CFString(location)) {
+       location = isA_CFString(location);
+       if (location == NULL) {
                _SCErrorSet(kSCStatusNoKey);
                goto done;
        }
@@ -80,7 +68,6 @@ SCDynamicStoreCopyLocation(SCDynamicStoreRef store)
     done :
 
 
-       if (tempSession)        CFRelease(store);
        if (dict)               CFRelease(dict);
 
        return location;
index 088b7697fbe8ababff712c00d658f07068ca8ef3..2342887f6bf552cffa91404090f382a720ed744c 100644 (file)
@@ -72,7 +72,7 @@ __setPrefsConfiguration(SCPreferencesRef      prefs,
                        CFDictionaryRef         config,
                        Boolean                 keepInactive)
 {
-       CFMutableDictionaryRef  newConfig       = NULL;
+       CFMutableDictionaryRef  newConfig       = NULL;
        Boolean                 ok;
 
        if ((config != NULL) && !isA_CFDictionary(config)) {
@@ -601,3 +601,50 @@ __remove_password(SCPreferencesRef prefs,
 
        return ok;
 }
+
+
+__private_extern__ Boolean
+__rank_to_str(SCNetworkServicePrimaryRank rank, CFStringRef *rankStr)
+{
+       switch (rank) {
+               case kSCNetworkServicePrimaryRankDefault :
+                       *rankStr = NULL;
+                       break;
+               case kSCNetworkServicePrimaryRankFirst :
+                       *rankStr = kSCValNetServicePrimaryRankFirst;
+                       break;
+               case kSCNetworkServicePrimaryRankLast :
+                       *rankStr = kSCValNetServicePrimaryRankLast;
+                       break;
+               case kSCNetworkServicePrimaryRankNever :
+                       *rankStr = kSCValNetServicePrimaryRankNever;
+                       break;
+               default :
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+__private_extern__ Boolean
+__str_to_rank(CFStringRef rankStr, SCNetworkServicePrimaryRank *rank)
+{
+       if (isA_CFString(rankStr)) {
+               if (CFEqual(rankStr, kSCValNetServicePrimaryRankFirst)) {
+                       *rank = kSCNetworkServicePrimaryRankFirst;
+               } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankLast)) {
+                       *rank = kSCNetworkServicePrimaryRankLast;
+               } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankNever)) {
+                       *rank = kSCNetworkServicePrimaryRankNever;
+               } else {
+                       return FALSE;
+               }
+       } else if (rankStr == NULL) {
+               *rank = kSCNetworkServicePrimaryRankDefault;
+       } else {
+               return FALSE;
+       }
+
+       return TRUE;
+}
index ead47e53f55332f3adb9e261c25f8375a6a955fc..ba253f07a72dee446486f19c9478d960cfee3437 100644 (file)
@@ -29,6 +29,7 @@
 #include <CoreFoundation/CFRuntime.h>
 #include <SystemConfiguration/SystemConfiguration.h>
 #include <SystemConfiguration/SCPreferencesPathKey.h>
+#include <SystemConfiguration/SCNetworkConfigurationPrivate.h>
 #include <IOKit/IOKitLib.h>
 
 
@@ -112,6 +113,9 @@ typedef struct {
        // prefs (for associated service, BOND interfaces, and VLAN interfaces)
        SCPreferencesRef        prefs;
 
+       // SCDynamicStore
+       SCDynamicStoreRef       store;
+
        // serviceID (NULL if not associated with a service)
        CFStringRef             serviceID;
 
@@ -309,6 +313,7 @@ Boolean
 __SCNetworkServiceExistsForInterface           (CFArrayRef             services,
                                                 SCNetworkInterfaceRef  interface);
 
+CF_RETURNS_RETAINED
 CFStringRef
 __SCNetworkServiceNextName                     (SCNetworkServiceRef    service);
 
@@ -380,6 +385,14 @@ __remove_password                          (SCPreferencesRef       prefs,
                                                 CFStringRef            unique_id,
                                                 CFDictionaryRef        *newConfig);
 
+Boolean
+__rank_to_str                                  (SCNetworkServicePrimaryRank    rank,
+                                                CFStringRef                    *rankStr);
+
+Boolean
+__str_to_rank                                  (CFStringRef                    rankStr,
+                                                SCNetworkServicePrimaryRank    *rank);
+
 __END_DECLS
 
 #endif /* _SCNETWORKCONFIGURATIONINTERNAL_H */
index e04c5ccdbe92bde947da7270c32156f31bf0cbe9..fb1987bf26fe730e5594ac437186183e3f6791aa 100644 (file)
@@ -44,7 +44,7 @@ __BEGIN_DECLS
  */
 
 #pragma mark -
-#pragma mark SCNetworkInterface configuration (typedefs, consts)
+#pragma mark SCNetworkInterface configuration (typedefs, consts, enums)
 
 /*!
        @const kSCNetworkInterfaceTypeBridge
@@ -79,6 +79,14 @@ extern const CFStringRef kSCNetworkInterfaceTypeVPN                                          __OSX_AVAILABLE_STARTIN
  */
 typedef SCNetworkInterfaceRef SCBridgeInterfaceRef;
 
+enum {
+       kSCNetworkServicePrimaryRankDefault     = 0,
+       kSCNetworkServicePrimaryRankFirst       = 1,
+       kSCNetworkServicePrimaryRankLast        = 2,
+       kSCNetworkServicePrimaryRankNever       = 3
+};
+typedef uint32_t       SCNetworkServicePrimaryRank;
+
 #pragma mark -
 #pragma mark SCNetworkInterface configuration (SPI)
 
@@ -162,6 +170,18 @@ _SCNetworkInterfaceCompare                         (const void                     *val1,
                                                         const void                     *val2,
                                                         void                           *context)       __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
 
+/*!
+       @function _SCNetworkInterfaceCopyActive
+       @discussion Creates an SCNetworkInterface and associated with interface name
+               and SCDynamicStoreRef
+       @param the interface name
+       @param the SCDynamicStoreRef
+       @result the SCNetworkInterface
+ */
+SCNetworkInterfaceRef
+_SCNetworkInterfaceCopyActive                          (SCDynamicStoreRef              store,
+                                                        CFStringRef                    bsdName)        __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0);
+
 /*!
        @function _SCNetworkInterfaceCopyAllWithPreferences
                Returns all network capable interfaces on the system.
@@ -229,6 +249,27 @@ _SCNetworkInterfaceCreateWithEntity                        (CFAllocatorRef                 allocator,
 SCNetworkInterfaceRef
 _SCNetworkInterfaceCreateWithIONetworkInterfaceObject  (io_object_t                    if_obj)         __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
 
+/*!
+       @function SCNetworkInterfaceGetPrimaryRank
+       @discussion We allow caller to retrieve the rank on an interface.
+               The key is stored in State:/Network/Interface/<ifname>/Service
+       @param the interface to get the rank
+       @result SCNetworkServicePrimaryRank
+ */
+SCNetworkServicePrimaryRank
+SCNetworkInterfaceGetPrimaryRank                       (SCNetworkInterfaceRef          interface)      __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0);
+
+/*!
+       @function SCNetworkInterfaceSetPrimaryRank
+       @discussion We allow caller to set an assertion on an interface.
+       @param the interface to set the rank assertion
+       @param the new rank to be set
+       @result TRUE if operation is successful; FALSE if an error was encountered.
+ */
+Boolean
+SCNetworkInterfaceSetPrimaryRank                       (SCNetworkInterfaceRef          interface,
+                                                        SCNetworkServicePrimaryRank    newRank)        __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0);
+
 #define        kSCNetworkInterfaceConfigurationActionKey               CFSTR("New Interface Detected Action")
 #define        kSCNetworkInterfaceConfigurationActionValueNone         CFSTR("None")
 #define        kSCNetworkInterfaceConfigurationActionValuePrompt       CFSTR("Prompt")
@@ -307,7 +348,7 @@ _SCNetworkInterfaceGetIOPath                                (SCNetworkInterfaceRef          interface)      __OSX_AVAILAB
                Zero if no entry ID is available.
  */
 uint64_t
-_SCNetworkInterfaceGetIORegistryEntryID                        (SCNetworkInterfaceRef          interface)      __OSX_AVAILABLE_STARTING(__MAC_10_7/*FIXME*/,__IPHONE_5_0);
+_SCNetworkInterfaceGetIORegistryEntryID                        (SCNetworkInterfaceRef          interface)      __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0);
 
 /*!
        @function _SCNetworkInterfaceIsBluetoothPAN
@@ -671,14 +712,6 @@ isA_SCNetworkService(CFTypeRef obj)
        return (isA_CFType(obj, SCNetworkServiceGetTypeID()));
 }
 
-enum {
-       kSCNetworkServicePrimaryRankDefault     = 0,
-       kSCNetworkServicePrimaryRankFirst       = 1,
-       kSCNetworkServicePrimaryRankLast        = 2,
-       kSCNetworkServicePrimaryRankNever       = 3
-};
-typedef uint32_t       SCNetworkServicePrimaryRank;
-
 /*!
        @function _SCNetworkServiceCompare
        @discussion Compares two SCNetworkService objects.
@@ -829,5 +862,4 @@ SCNetworkSetSetSelectedVPNService                   (SCNetworkSetRef                set,
                                                         SCNetworkServiceRef            service)        __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);
 
 __END_DECLS
-
 #endif /* _SCNETWORKCONFIGURATIONPRIVATE_H */
index abaefeefac1b7125f1720b8825abcdd2e2438eb0..e54ea073c63ad8df05f8193ace89ef875a89144c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -88,6 +88,12 @@ typedef struct {
        /* service */
        SCNetworkServiceRef             service;
 
+       /* client info (if we are proxying for another process */
+       mach_port_t                     client_audit_session;
+       uid_t                           client_uid;
+       gid_t                           client_gid;
+       pid_t                           client_pid;
+
        /* ref to PPP controller for control messages */
        mach_port_t                     session_port;
 
@@ -105,9 +111,9 @@ typedef struct {
        CFMutableArrayRef               rlList;
 
        /* SCNetworkConnectionSetDispatchQueue */
+       dispatch_group_t                dispatchGroup;
        dispatch_queue_t                dispatchQueue;
-       dispatch_queue_t                callbackQueue;
-       dispatch_source_t               callbackSource;
+       dispatch_source_t               dispatchSource;
 
 } SCNetworkConnectionPrivate, *SCNetworkConnectionPrivateRef;
 
@@ -146,6 +152,13 @@ __SCNetworkConnectionDeallocate(CFTypeRef cf)
        /* release resources */
        pthread_mutex_destroy(&connectionPrivate->lock);
 
+       if (connectionPrivate->client_audit_session != MACH_PORT_NULL) {
+               mach_port_mod_refs(mach_task_self(),
+                                  connectionPrivate->client_audit_session,
+                                  MACH_PORT_RIGHT_SEND,
+                                  -1);
+       }
+
        if (connectionPrivate->rls != NULL) {
                CFRunLoopSourceInvalidate(connectionPrivate->rls);
                CFRelease(connectionPrivate->rls);
@@ -334,6 +347,11 @@ __SCNetworkConnectionCreatePrivate(CFAllocatorRef          allocator,
        /* save the service */
        connectionPrivate->service = CFRetain(service);
 
+       connectionPrivate->client_audit_session = MACH_PORT_NULL;
+       connectionPrivate->client_uid = geteuid();
+       connectionPrivate->client_gid = getegid();
+       connectionPrivate->client_pid = getpid();
+
        connectionPrivate->rlsFunction = callout;
 
        if (context) {
@@ -396,6 +414,16 @@ __SCNetworkConnectionServerPort(kern_return_t *status)
 }
 
 
+#if    ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) && !TARGET_IPHONE_SIMULATOR
+#define        HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
+#endif
+
+
+#if    ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) && !TARGET_IPHONE_SIMULATOR
+#define        HAVE_PPPCONTROLLER_ATTACHWITHPROXY
+#endif
+
+
 static mach_port_t
 __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate)
 {
@@ -408,7 +436,10 @@ __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate
        int             sc_status       = kSCStatusFailed;
        mach_port_t     server          = scnc_server;
        kern_return_t   status          = KERN_SUCCESS;
+
+#ifdef HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
        mach_port_t     au_session      = MACH_PORT_NULL;
+#endif // HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
 
        if (connectionPrivate->session_port != MACH_PORT_NULL) {
                return connectionPrivate->session_port;
@@ -428,7 +459,9 @@ __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate
                mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1);
        }
 
+#ifdef HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
        au_session = audit_session_self();
+#endif // HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
 
        // open a new session with the server
        while (TRUE) {
@@ -455,14 +488,46 @@ __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate
                }
 
                if (server != MACH_PORT_NULL) {
-                       status = pppcontroller_attach(server,
-                                                     data,
-                                                     dataLen,
-                                                     bootstrap_port,
-                                                     notify_port,
-                                                     au_session,
-                                                     &connectionPrivate->session_port,
-                                                     &sc_status);
+#ifdef HAVE_PPPCONTROLLER_ATTACHWITHPROXY
+                       if ((connectionPrivate->client_audit_session == MACH_PORT_NULL) &&
+                           (connectionPrivate->client_uid == geteuid()) &&
+                           (connectionPrivate->client_gid == getegid()) &&
+                           (connectionPrivate->client_pid == getpid())
+                          ) {
+#endif // HAVE_PPPCONTROLLER_ATTACHWITHPROXY
+                               status = pppcontroller_attach(server,
+                                                             data,
+                                                             dataLen,
+                                                             bootstrap_port,
+                                                             notify_port,
+#ifdef HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
+                                                             au_session,
+#endif // HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
+                                                             &connectionPrivate->session_port,
+                                                             &sc_status);
+#ifdef HAVE_PPPCONTROLLER_ATTACHWITHPROXY
+                       } else {
+                               mach_port_t     client_au_session;
+
+                               if (connectionPrivate->client_audit_session == MACH_PORT_NULL) {
+                                       client_au_session = au_session;
+                               } else {
+                                       client_au_session = connectionPrivate->client_audit_session;
+                               }
+
+                               status = pppcontroller_attach_proxy(server,
+                                                                   data,
+                                                                   dataLen,
+                                                                   bootstrap_port,
+                                                                   notify_port,
+                                                                   client_au_session,
+                                                                   connectionPrivate->client_uid,
+                                                                   connectionPrivate->client_gid,
+                                                                   connectionPrivate->client_pid,
+                                                                   &connectionPrivate->session_port,
+                                                                   &sc_status);
+                       }
+#endif // HAVE_PPPCONTROLLER_ATTACHWITHPROXY
                        if (status == KERN_SUCCESS) {
                                if (sc_status != kSCStatusOK) {
                                        SCLog(TRUE, LOG_DEBUG,
@@ -598,9 +663,12 @@ __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate
     done :
 
        // clean up
-       if (au_session != MACH_PORT_NULL) {
+
+#ifdef HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
+       if (au_session != MACH_PORT_NULL){
                (void)mach_port_deallocate(mach_task_self(), au_session);
        }
+#endif // HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION
 
        if (dataRef != NULL)    CFRelease(dataRef);
 
@@ -649,6 +717,7 @@ static Boolean
 __SCNetworkConnectionReconnectNotifications(SCNetworkConnectionRef connection)
 {
        SCNetworkConnectionPrivateRef   connectionPrivate       = (SCNetworkConnectionPrivateRef)connection;
+       dispatch_group_t                dispatchGroup           = NULL;
        dispatch_queue_t                dispatchQueue           = NULL;
        Boolean                         ok                      = TRUE;
        CFArrayRef                      rlList                  = NULL;
@@ -663,7 +732,14 @@ __SCNetworkConnectionReconnectNotifications(SCNetworkConnectionRef connection)
                rlList = CFArrayCreateCopy(NULL, connectionPrivate->rlList);
        }
        if (connectionPrivate->dispatchQueue != NULL) {
+               // save dispatchQueue, release reference when we've queue'd blocks
+               // complete, allow re-scheduling
+               dispatchGroup = connectionPrivate->dispatchGroup;
+               connectionPrivate->dispatchGroup = NULL;
                dispatchQueue = connectionPrivate->dispatchQueue;
+               connectionPrivate->dispatchQueue = NULL;
+
+               // and take an extra reference for rescheduling
                dispatch_retain(dispatchQueue);
        }
 
@@ -677,28 +753,23 @@ __SCNetworkConnectionReconnectNotifications(SCNetworkConnectionRef connection)
                CFRelease(connectionPrivate->rls);
                connectionPrivate->rls = NULL;
        }
-       if (connectionPrivate->callbackSource != NULL) {
-               dispatch_source_cancel(connectionPrivate->callbackSource);
-               if (connectionPrivate->callbackQueue != dispatch_get_current_queue()) {
-                       // ensure the cancellation has completed
-                       dispatch_sync(connectionPrivate->callbackQueue, ^{});
-               }
-               dispatch_release(connectionPrivate->callbackSource);
-               connectionPrivate->callbackSource = NULL;
-       }
-       if (connectionPrivate->callbackQueue != NULL) {
-               dispatch_release(connectionPrivate->callbackQueue);
-               connectionPrivate->callbackQueue = NULL;
-       }
-       if (connectionPrivate->dispatchQueue != NULL) {
-               dispatch_release(connectionPrivate->dispatchQueue);
-               connectionPrivate->dispatchQueue = NULL;
+       if (connectionPrivate->dispatchSource != NULL) {
+               dispatch_source_cancel(connectionPrivate->dispatchSource);
+               connectionPrivate->dispatchSource = NULL;
        }
 
        connectionPrivate->scheduled = FALSE;
 
        pthread_mutex_unlock(&connectionPrivate->lock);
 
+       if (dispatchGroup != NULL) {
+               dispatch_group_notify(dispatchGroup, dispatchQueue, ^{
+                       // release group/queue references
+                       dispatch_release(dispatchQueue);
+                       dispatch_release(dispatchGroup);        // releases our connection reference
+               });
+       }
+
        // re-schedule
        if (rlList != NULL) {
                CFIndex i;
@@ -905,6 +976,45 @@ SCNetworkConnectionCopyServiceID(SCNetworkConnectionRef connection)
 }
 
 
+Boolean
+SCNetworkConnectionSetClientInfo(SCNetworkConnectionRef        connection,
+                                mach_port_t            client_audit_session,
+                                uid_t                  client_uid,
+                                gid_t                  client_gid,
+                                pid_t                  client_pid)
+{
+       SCNetworkConnectionPrivateRef   connectionPrivate       = (SCNetworkConnectionPrivateRef)connection;
+
+       if (!isA_SCNetworkConnection(connection)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // save client bootstrap port
+       if (connectionPrivate->client_audit_session != MACH_PORT_NULL) {
+               mach_port_mod_refs(mach_task_self(),
+                                  connectionPrivate->client_audit_session,
+                                  MACH_PORT_RIGHT_SEND,
+                                  -1);
+               connectionPrivate->client_audit_session = MACH_PORT_NULL;
+       }
+       connectionPrivate->client_audit_session = client_audit_session;
+       if (connectionPrivate->client_audit_session != MACH_PORT_NULL) {
+               mach_port_mod_refs(mach_task_self(),
+                                  connectionPrivate->client_audit_session,
+                                  MACH_PORT_RIGHT_SEND,
+                                  1);
+       }
+
+       // save client UID, GID, and PID
+       connectionPrivate->client_uid = client_uid;
+       connectionPrivate->client_gid = client_gid;
+       connectionPrivate->client_pid = client_pid;
+
+       return TRUE;
+}
+
+
 CFDictionaryRef
 SCNetworkConnectionCopyStatistics(SCNetworkConnectionRef connection)
 {
@@ -1449,30 +1559,6 @@ SCNetworkConnectionCopyUserOptions(SCNetworkConnectionRef connection)
 }
 
 
-static boolean_t
-SCNetworkConnectionNotifyMIGCallback(mach_msg_header_t *message, mach_msg_header_t *reply)
-{
-       SCNetworkConnectionPrivateRef   connectionPrivate = dispatch_get_context(dispatch_get_current_queue());
-
-       if (connectionPrivate != NULL) {
-               mach_msg_empty_rcv_t    *buf    = malloc(sizeof(*buf));
-
-               bcopy(message, buf, sizeof(*buf));
-               CFRetain(connectionPrivate);
-               dispatch_async(connectionPrivate->dispatchQueue, ^{
-                       __SCNetworkConnectionCallBack(connectionPrivate->notify_port,
-                                                     buf,
-                                                     sizeof(*buf),
-                                                     connectionPrivate);
-                       CFRelease(connectionPrivate);
-                       free(buf);
-               });
-       }
-       reply->msgh_remote_port = MACH_PORT_NULL;
-       return false;
-}
-
-
 static Boolean
 __SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef        connection,
                                         CFRunLoopRef           runLoop,
@@ -1529,42 +1615,80 @@ __SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection,
        }
 
        if (queue != NULL) {
-               mach_port_t     mp;
-               char            qname[256];
-
-               connectionPrivate->dispatchQueue = queue;
-               dispatch_retain(connectionPrivate->dispatchQueue);
-
-               snprintf(qname, sizeof(qname), "com.apple.SCNetworkConnection.%p", connection);
-               connectionPrivate->callbackQueue = dispatch_queue_create(qname, NULL);
-               if (connectionPrivate->callbackQueue == NULL){
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkConnection dispatch_queue_create() failed"));
-                       goto fail;
-               }
-               CFRetain(connection);   // Note: will be released when the dispatch queue is released
-               dispatch_set_context(connectionPrivate->callbackQueue, connectionPrivate);
-               dispatch_set_finalizer_f(connectionPrivate->callbackQueue, (dispatch_function_t)CFRelease);
+               mach_port_t             mp;
+               dispatch_source_t       source;
 
                mp = CFMachPortGetPort(connectionPrivate->notify_port);
-               connectionPrivate->callbackSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
-                                                                          mp,
-                                                                          0,
-                                                                          connectionPrivate->callbackQueue);
-               if (connectionPrivate->callbackSource == NULL) {
+               source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue);
+               if (source == NULL) {
                        SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkConnection dispatch_source_create() failed"));
-                       goto fail;
+                       _SCErrorSet(kSCStatusFailed);
+                       goto done;
                }
-               dispatch_source_set_event_handler(connectionPrivate->callbackSource, ^{
-                       union MaxMsgSize {
-                               mach_msg_empty_rcv_t            normal;
+
+               // have our dispatch source hold a reference to the notification CFMachPort
+               CFRetain(connectionPrivate->notify_port);
+               dispatch_set_context(source, (void *)connectionPrivate->notify_port);
+               dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease);
+
+               // retain the dispatch queue
+               connectionPrivate->dispatchQueue = queue;
+               dispatch_retain(connectionPrivate->dispatchQueue);
+
+               //
+               // We've taken a reference to the callers dispatch_queue and we
+               // want to hold on to that reference until we've processed any/all
+               // notifications.  To facilitate this we create a group, dispatch
+               // any notification blocks to via that group, and when the caller
+               // has told us to stop the notifications (unschedule) we wait for
+               // the group to empty and use the group's finalizer to release
+               // our reference to the SCNetworkConnection.
+               //
+               connectionPrivate->dispatchGroup = dispatch_group_create();
+               CFRetain(connection);
+               dispatch_set_context(connectionPrivate->dispatchGroup, (void *)connection);
+               dispatch_set_finalizer_f(connectionPrivate->dispatchGroup, (dispatch_function_t)CFRelease);
+
+               dispatch_source_set_event_handler(source, ^{
+                       kern_return_t   kr;
+                       union {
+                               u_int8_t                        buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE];
+                               mach_msg_empty_rcv_t            msg;
                                mach_no_senders_notification_t  no_senders;
-                       };
+                       } notify_msg;
+                       CFMachPortRef   notify_port;
+
+                       kr = mach_msg(&notify_msg.msg.header,   // msg
+                                     MACH_RCV_MSG,             // options
+                                     0,                        // send_size
+                                     sizeof(notify_msg),       // rcv_size
+                                     mp,                       // rcv_name
+                                     MACH_MSG_TIMEOUT_NONE,    // timeout
+                                     MACH_PORT_NULL);          // notify
+                       if (kr != KERN_SUCCESS) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("SCDynamicStore notification handler, kr=0x%x"),
+                                     kr);
+                               return;
+                       }
 
-                       dispatch_mig_server(connectionPrivate->callbackSource,
-                                           sizeof(union MaxMsgSize),
-                                           SCNetworkConnectionNotifyMIGCallback);
+                       CFRetain(connection);
+                       notify_port = dispatch_get_context(source);
+                       dispatch_group_async(connectionPrivate->dispatchGroup, connectionPrivate->dispatchQueue, ^{
+                               __SCNetworkConnectionCallBack(notify_port,
+                                                             (void *)&notify_msg.msg,
+                                                             sizeof(notify_msg),
+                                                             (void *)connection);
+                               CFRelease(connection);
+                       });
                });
-               dispatch_resume(connectionPrivate->callbackSource);
+
+               dispatch_source_set_cancel_handler(source, ^{
+                       dispatch_release(source);
+               });
+
+               connectionPrivate->dispatchSource = source;
+               dispatch_resume(source);
        } else {
                if (!_SC_isScheduled(NULL, runLoop, runLoopMode, connectionPrivate->rlList)) {
                        /*
@@ -1578,24 +1702,6 @@ __SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef  connection,
        }
 
        ok = TRUE;
-       goto done;
-
-    fail :
-
-       if (connectionPrivate->callbackSource != NULL) {
-               dispatch_source_cancel(connectionPrivate->callbackSource);
-               dispatch_release(connectionPrivate->callbackSource);
-               connectionPrivate->callbackSource = NULL;
-       }
-       if (connectionPrivate->callbackQueue != NULL) {
-               dispatch_release(connectionPrivate->callbackQueue);
-               connectionPrivate->callbackQueue = NULL;
-       }
-       if (connectionPrivate->dispatchQueue != NULL) {
-               dispatch_release(connectionPrivate->dispatchQueue);
-               connectionPrivate->dispatchQueue = NULL;
-       }
-       _SCErrorSet(kSCStatusFailed);
 
     done :
 
@@ -1611,12 +1717,17 @@ __SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef       connection,
                                           dispatch_queue_t             queue)
 {
        SCNetworkConnectionPrivateRef   connectionPrivate       = (SCNetworkConnectionPrivateRef)connection;
+       dispatch_group_t                drainGroup              = NULL;
+       dispatch_queue_t                drainQueue              = NULL;
        int                             sc_status               = kSCStatusFailed;
        CFIndex                         n                       = 0;
        Boolean                         ok                      = FALSE;
        mach_port_t                     session_port;
        kern_return_t                   status;
 
+       // hold a reference while we unschedule
+       CFRetain(connection);
+
        pthread_mutex_lock(&connectionPrivate->lock);
 
        if ((runLoop != NULL) && !connectionPrivate->scheduled) {                       // if we should be scheduled (but are not)
@@ -1635,17 +1746,18 @@ __SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef       connection,
                goto done;
        }
 
-       if (runLoop == NULL) {
-               dispatch_source_cancel(connectionPrivate->callbackSource);
-               if (connectionPrivate->callbackQueue != dispatch_get_current_queue()) {
-                       // ensure the cancellation has completed
-                       dispatch_sync(connectionPrivate->callbackQueue, ^{});
+       if (connectionPrivate->dispatchQueue != NULL) {
+               // cancel dispatchSource
+               if (connectionPrivate->dispatchSource != NULL) {
+                       dispatch_source_cancel(connectionPrivate->dispatchSource);
+                       connectionPrivate->dispatchSource = NULL;
                }
-               dispatch_release(connectionPrivate->callbackSource);
-               connectionPrivate->callbackSource = NULL;
-               dispatch_release(connectionPrivate->callbackQueue);
-               connectionPrivate->callbackQueue = NULL;
-               dispatch_release(connectionPrivate->dispatchQueue);
+
+               // save dispatchQueue/group, release reference when all queue'd blocks
+               // have been processed, allow re-scheduling
+               drainGroup = connectionPrivate->dispatchGroup;
+               connectionPrivate->dispatchGroup = NULL;
+               drainQueue = connectionPrivate->dispatchQueue;
                connectionPrivate->dispatchQueue = NULL;
        } else {
                if (!_SC_unschedule(connection, runLoop, runLoopMode, connectionPrivate->rlList, FALSE)) {
@@ -1697,6 +1809,18 @@ __SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef        connection,
     done :
 
        pthread_mutex_unlock(&connectionPrivate->lock);
+
+       if (drainGroup != NULL) {
+               dispatch_group_notify(drainGroup, drainQueue, ^{
+                       // release group/queue references
+                       dispatch_release(drainQueue);
+                       dispatch_release(drainGroup);   // releases our connection reference
+               });
+       }
+
+       // release our reference
+       CFRelease(connection);
+
        return ok;
 }
 
@@ -1780,8 +1904,8 @@ static int                onDemand_notify_token   = -1;
 /*
  *     return TRUE if domain1 ends with domain2, and will check for trailing "."
  */
-static Boolean
-domainEndsWithDomain(CFStringRef domain1, CFStringRef domain2)
+Boolean
+_SC_domainEndsWithDomain(CFStringRef compare_domain, CFStringRef match_domain)
 {
        CFRange         range;
        Boolean         ret             = FALSE;
@@ -1789,29 +1913,44 @@ domainEndsWithDomain(CFStringRef domain1, CFStringRef domain2)
        Boolean         s1_created      = FALSE;
        CFStringRef     s2              = NULL;
        Boolean         s2_created      = FALSE;
+       CFStringRef     s3              = NULL;
 
-       if (CFStringHasSuffix(domain1, CFSTR("."))) {
+       if (CFStringHasSuffix(compare_domain, CFSTR("."))) {
                range.location = 0;
-               range.length = CFStringGetLength(domain1) - 1;
-               s1 = CFStringCreateWithSubstring(NULL, domain1, range);
+               range.length = CFStringGetLength(compare_domain) - 1;
+               s1 = CFStringCreateWithSubstring(NULL, compare_domain, range);
                if (s1 == NULL) {
                        goto done;
                }
                s1_created = TRUE;
        } else {
-               s1 = domain1;
+               s1 = compare_domain;
        }
 
-       if (CFStringHasSuffix(domain2, CFSTR("."))) {
+       if (CFStringHasSuffix(match_domain, CFSTR("."))) {
                range.location = 0;
-               range.length = CFStringGetLength(domain2) - 1;
-               s2 = CFStringCreateWithSubstring(NULL, domain2, range);
+               range.length = CFStringGetLength(match_domain) - 1;
+               s2 = CFStringCreateWithSubstring(NULL, match_domain, range);
                if (s2 == NULL) {
                        goto done;
                }
                s2_created = TRUE;
        } else {
-               s2 = domain2;
+               s2 = match_domain;
+       }
+
+       if (CFStringHasPrefix(s2, CFSTR("*."))) {
+               range.location = 2;
+               range.length = CFStringGetLength(s2)-2;
+               s3 = CFStringCreateWithSubstring(NULL, s2, range);
+               if (s3 == NULL) {
+                       goto done;
+               }
+               if (s2_created) {
+                       CFRelease(s2);
+               }
+               s2 = s3;
+               s2_created = TRUE;
        }
 
        ret = CFStringHasSuffix(s1, s2);
@@ -1949,7 +2088,7 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef           *storeP,
                                continue;
                        }
 
-                       if (domainEndsWithDomain(hostName, domain)) {
+                       if (_SC_domainEndsWithDomain(hostName, domain)) {
                                CFArrayRef                      exceptions;
                                int                             exceptionsCount;
                                int                             exceptionsIndex;
@@ -1968,7 +2107,7 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef           *storeP,
                                                continue;
                                        }
 
-                                       if (domainEndsWithDomain(hostName, exception)) {
+                                       if (_SC_domainEndsWithDomain(hostName, exception)) {
                                                // found matching exception
                                                if (_sc_debug || (debug > 0)) {
                                                        SCLog(TRUE, LOG_INFO, CFSTR("OnDemand match exception"));
@@ -1980,6 +2119,8 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef           *storeP,
                                // if we have a matching domain and there were no exceptions
                                // then we pass back the OnDemand info
 
+                               ok = TRUE;
+
                                if (!CFDictionaryGetValueIfPresent(trigger,
                                                                   kSCNetworkConnectionOnDemandStatus,
                                                                   (const void **)&num) ||
@@ -1994,20 +2135,45 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef         *storeP,
                                if (connectionServiceID != NULL) {
                                        *connectionServiceID = CFDictionaryGetValue(trigger, kSCNetworkConnectionOnDemandServiceID);
                                        *connectionServiceID = isA_CFString(*connectionServiceID);
-                                       if (*connectionServiceID != NULL) {
+                                       if ((*connectionServiceID != NULL) && (CFStringGetLength(*connectionServiceID) > 0)) {
                                                CFRetain(*connectionServiceID);
-                                       }
+                                       } else {
+                                               SCLog(TRUE, LOG_INFO,
+                                                     CFSTR("OnDemand%s configuration error, no serviceID"),
+                                                     onDemandRetry ? " (on retry)" : "");
 
+                                               *connectionServiceID = NULL;
+                                               ok = FALSE;
+                                       }
                                }
 
                                if (vpnRemoteAddress != NULL) {
                                        *vpnRemoteAddress = CFDictionaryGetValue(trigger, kSCNetworkConnectionOnDemandRemoteAddress);
                                        *vpnRemoteAddress = isA_CFString(*vpnRemoteAddress);
-                                       if (*vpnRemoteAddress != NULL) {
+                                       if ((*vpnRemoteAddress != NULL) && (CFStringGetLength(*vpnRemoteAddress) > 0)) {
                                                CFRetain(*vpnRemoteAddress);
+                                       } else {
+                                               SCLog(TRUE, LOG_INFO,
+                                                     CFSTR("OnDemand%s configuration error, no server address"),
+                                                     onDemandRetry ? " (on retry)" : "");
+
+                                               *vpnRemoteAddress = NULL;
+                                               ok = FALSE;
                                        }
                                }
 
+                               if (!ok) {
+                                       if ((connectionServiceID != NULL) && (*connectionServiceID != NULL)) {
+                                               CFRelease(*connectionServiceID);
+                                               *connectionServiceID = NULL;
+                                       }
+                                       if ((vpnRemoteAddress != NULL) && (*vpnRemoteAddress != NULL)) {
+                                               CFRelease(*vpnRemoteAddress);
+                                               *vpnRemoteAddress = NULL;
+                                       }
+                                       continue;
+                               }
+
                                if (_sc_debug || (debug > 0)) {
                                        SCLog(TRUE, LOG_INFO,
                                              CFSTR("OnDemand%s match, connection status = %d"),
@@ -2015,7 +2181,6 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef           *storeP,
                                              onDemandStatus);
                                }
 
-                               ok = TRUE;
                                goto done;
                        }
                }
@@ -2231,7 +2396,7 @@ SCNetworkConnectionCopyUserPreferences(CFDictionaryRef    selectionOptions,
                                                        catchAllConfig = configIndex;
                                                }
 
-                                               if (domainEndsWithDomain(hostName, domain)) {
+                                               if (_SC_domainEndsWithDomain(hostName, domain)) {
                                                        // found matching configuration
                                                        *serviceID = serviceName;
                                                        CFRetain(*serviceID);
index 381f75389e925b73da53a6268b03f793a8b4a689..6e98de14f609251d79db55e239580df3e6d96ac3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -530,7 +530,7 @@ SCUserPreferencesRemove(SCUserPreferencesRef userPreferences)
 }
 
 
-static CFDictionaryRef
+static CF_RETURNS_RETAINED CFDictionaryRef
 setCurrentCallout(CFStringRef          serviceID,
                  CFDictionaryRef       current,
                  void                  *context1,
@@ -644,7 +644,7 @@ SCUserPreferencesCopyName(SCUserPreferencesRef userPreferences)
 }
 
 
-static CFDictionaryRef
+static CF_RETURNS_RETAINED CFDictionaryRef
 setNameCallout(CFStringRef     serviceID,
               CFDictionaryRef  current,
               void             *context1,
@@ -790,7 +790,7 @@ SCUserPreferencesCopyInterfaceConfiguration(SCUserPreferencesRef    userPreferences
 }
 
 
-static CFDictionaryRef
+static CF_RETURNS_RETAINED CFDictionaryRef
 setInterfaceConfigurationCallout(CFStringRef           serviceID,
                                  CFDictionaryRef       current,
                                  void                  *context1,
index a3ec9ff2b09efed975ef51a5518e2bfa5d6e1d51..d790dbb69223bf73e495b54114c94cd7ba98546e 100644 (file)
@@ -68,6 +68,13 @@ SCNetworkConnectionSuspend                   (SCNetworkConnectionRef         connection)             __OSX_AVAILAB
 Boolean
 SCNetworkConnectionResume                      (SCNetworkConnectionRef         connection)             __OSX_AVAILABLE_STARTING(__MAC_10_3,__IPHONE_2_0);
 
+Boolean
+SCNetworkConnectionSetClientInfo               (SCNetworkConnectionRef         connection,
+                                                mach_port_t                    client_audit_session,
+                                                uid_t                          client_uid,
+                                                gid_t                          client_gid,
+                                                pid_t                          client_pid)             __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0);
+
 
 #pragma mark -
 #pragma mark SCNetworkConnection "VPN on Demand" SPIs
@@ -137,7 +144,6 @@ SCNetworkConnectionResume                   (SCNetworkConnectionRef         connection)             __OSX_AVAILABL
 #define kSCNetworkConnectionOnDemandMatchDomainsNever          CFSTR("OnDemandMatchDomainsNever")
 
 
-__private_extern__
 Boolean
 __SCNetworkConnectionCopyOnDemandInfoWithName  (SCDynamicStoreRef              *storeP,
                                                 CFStringRef                    nodeName,
index 6c5fc487a90f16a6261966e8055aeb8f898faa5f..a9cbfc0476d746597e02faa9739708baf6eb5a7d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -161,6 +161,7 @@ static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4  = {
        NULL,                                   // localization arg2
        NULL,                                   // [layered] interface
        NULL,                                   // prefs
+       NULL,                                   // store
        NULL,                                   // serviceID
        NULL,                                   // unsaved
        NULL,                                   // entity_device
@@ -203,6 +204,7 @@ static SCNetworkInterfacePrivate __kSCNetworkInterfaceLoopback      = {
        NULL,                                   // localization arg2
        NULL,                                   // [layered] interface
        NULL,                                   // prefs
+       NULL,                                   // store
        NULL,                                   // serviceID
        NULL,                                   // unsaved
        NULL,                                   // entity_device
@@ -515,6 +517,9 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf)
        if (interfacePrivate->prefs != NULL)
                CFRelease(interfacePrivate->prefs);
 
+       if (interfacePrivate->store != NULL)
+               CFRelease(interfacePrivate->store);
+
        if (interfacePrivate->serviceID != NULL)
                CFRelease(interfacePrivate->serviceID);
 
@@ -748,6 +753,7 @@ __SCNetworkInterfaceCreatePrivate(CFAllocatorRef    allocator,
        interfacePrivate->localized_arg2                = NULL;
        interfacePrivate->interface                     = (interface != NULL) ? CFRetain(interface) : NULL;
        interfacePrivate->prefs                         = (prefs     != NULL) ? CFRetain(prefs)     : NULL;
+       interfacePrivate->store                         = NULL;
        interfacePrivate->serviceID                     = (serviceID != NULL) ? CFRetain(serviceID) : NULL;
        interfacePrivate->unsaved                       = NULL;
        interfacePrivate->entity_device                 = NULL;
@@ -832,7 +838,8 @@ __SCNetworkInterfaceSupportsVLAN(CFStringRef bsd_if)
        }
 
        // check the link type and hwassist flags
-       ifm = (struct if_msghdr *)buf;
+       // ALIGN: buf is aligned
+       ifm = (struct if_msghdr *)(void *)buf;
        switch (ifm->ifm_type) {
                case RTM_IFINFO : {
 #if    defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU)
@@ -947,7 +954,7 @@ _SCVLANInterfaceCreatePrivate(CFAllocatorRef                allocator,
 #pragma mark Interface ordering
 
 
-static CFArrayRef
+static CF_RETURNS_RETAINED CFArrayRef
 split_path(CFStringRef path)
 {
        CFArrayRef              components;
@@ -1239,7 +1246,7 @@ static const CFStringRef  slot_prefixes[] = {
 };
 
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name)
 {
        kern_return_t           kr;
@@ -1335,7 +1342,7 @@ compare_bsdNames(const void *val1, const void *val2, void *context)
 }
 
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 pci_port(CFTypeRef slot_name, int ift, CFStringRef bsdName)
 {
        CFIndex                 n;
@@ -2485,7 +2492,7 @@ createInterface(io_registry_entry_t interface, processInterface func)
 }
 
 
-static CFArrayRef
+static CF_RETURNS_RETAINED CFArrayRef
 findMatchingInterfaces(CFDictionaryRef matching, processInterface func)
 {
        CFMutableArrayRef       interfaces;
@@ -2686,7 +2693,7 @@ __addExtendedConfigurationType(const void *key, const void *value, void *context
 }
 
 
-static CFArrayRef
+static CF_RETURNS_RETAINED CFArrayRef
 extendedConfigurationTypes(SCNetworkInterfaceRef interface)
 {
        CFIndex                         i;
@@ -2975,6 +2982,7 @@ findInterface(CFArrayRef interfaces, CFStringRef match_if)
        return NULL;
 }
 
+#if    !TARGET_OS_IPHONE
 static SCNetworkInterfaceRef
 findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice)
 {
@@ -2993,6 +3001,7 @@ findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice)
        }
        return interface;
 }
+#endif // !TARGET_OS_IPHONE
 
 static SCNetworkInterfaceRef
 findBridgeInterface(SCPreferencesRef prefs, CFStringRef ifDevice)
@@ -3047,9 +3056,11 @@ _SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef              allocator,
                                           &kCFTypeDictionaryValueCallBacks);
        CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, bsdName);
 
+#if    !TARGET_OS_IPHONE
        if ((flags & kIncludeBondInterfaces) == 0) {
                CFDictionarySetValue(entity, CFSTR("_NO_BOND_INTERFACES_"), kCFBooleanTrue);
        }
+#endif // !TARGET_OS_IPHONE
 
        if ((flags & kIncludeBridgeInterfaces) == 0) {
                CFDictionarySetValue(entity, CFSTR("_NO_BRIDGE_INTERFACES_"), kCFBooleanTrue);
@@ -3321,10 +3332,11 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef              allocator,
                                if (prefs == NULL) {
                                        break;
                                }
+#if    !TARGET_OS_IPHONE
                                if (!CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BOND_INTERFACES_"))) {
                                        interfacePrivate = (SCNetworkInterfacePrivateRef)findBondInterface(prefs, ifDevice);
                                }
-
+#endif // !TARGET_OS_IPHONE
                                if ((interfacePrivate == NULL)
                                    && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BRIDGE_INTERFACES_"))) {
                                        interfacePrivate = (SCNetworkInterfacePrivateRef)findBridgeInterface(prefs, ifDevice);
@@ -3512,6 +3524,7 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef                allocator,
                __SCNetworkInterfaceSetService((SCNetworkInterfaceRef)interfacePrivate,
                                               service);
 
+#if    !TARGET_OS_IPHONE
                // set prefs & serviceID to Bond member interfaces
                if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBond)) {
                        CFIndex         i;
@@ -3527,6 +3540,7 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef                allocator,
                                __SCNetworkInterfaceSetService(member, service);
                        }
                }
+#endif // !TARGET_OS_IPHONE
 
                // set prefs & serviceID to Bridge member interfaces
                if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBridge)) {
@@ -3654,6 +3668,50 @@ __SCNetworkInterfaceCopyAll_RS232()
 }
 
 
+#if    !TARGET_OS_IPHONE
+static void
+addBTPANInterface(SCPreferencesRef prefs, CFMutableArrayRef all_interfaces)
+{
+       CFIndex         i;
+       CFIndex         n;
+       CFArrayRef      services;
+
+       n = CFArrayGetCount(all_interfaces);
+       for (i = 0; i < n; i++) {
+               SCNetworkInterfaceRef   interface;
+
+               interface = CFArrayGetValueAtIndex(all_interfaces, i);
+               if (_SCNetworkInterfaceIsBluetoothPAN(interface)) {
+                       // if we already have a BT-PAN interface
+                       return;
+               }
+       }
+
+       services = SCNetworkServiceCopyAll(prefs);
+       if (services != NULL) {
+               n = CFArrayGetCount(services);
+               for (i = 0; i < n; i++) {
+                       SCNetworkInterfaceRef   interface;
+                       SCNetworkServiceRef     service;
+
+                       service = CFArrayGetValueAtIndex(services, i);
+                       interface = SCNetworkServiceGetInterface(service);
+                       if ((interface != NULL) &&
+                           _SCNetworkInterfaceIsBluetoothPAN(interface)) {
+                               // include BT-PAN interface
+                               CFArrayAppendValue(all_interfaces, interface);
+                               break;
+                       }
+               }
+
+               CFRelease(services);
+       }
+
+       return;
+}
+#endif // !TARGET_OS_IPHONE
+
+
 static void
 add_interfaces(CFMutableArrayRef all_interfaces, CFArrayRef new_interfaces)
 {
@@ -3783,11 +3841,13 @@ _SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs)
                }
        }
        if (prefs != NULL) {
+#if    !TARGET_OS_IPHONE
                new_interfaces = SCBondInterfaceCopyAll(prefs);
                if (new_interfaces != NULL) {
                        add_interfaces(all_interfaces, new_interfaces);
                        CFRelease(new_interfaces);
                }
+#endif // !TARGET_OS_IPHONE
 
                new_interfaces = SCBridgeInterfaceCopyAll(prefs);
                if (new_interfaces != NULL) {
@@ -3801,6 +3861,11 @@ _SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs)
                        CFRelease(new_interfaces);
                }
 
+#if    !TARGET_OS_IPHONE
+               // add BT-PAN interface
+               addBTPANInterface(prefs, all_interfaces);
+#endif // !TARGET_OS_IPHONE
+
                if (temp_preferences) CFRelease(prefs);
        }
 
@@ -4740,25 +4805,18 @@ _SCNetworkInterfaceForceConfigurationRefresh(CFStringRef ifName)
 {
        CFStringRef             key;
        Boolean                 ok     = FALSE;
-       SCDynamicStoreRef       store;
 
        if (!isA_CFString(ifName)) {
                _SCErrorSet(kSCStatusInvalidArgument);
                return FALSE;
        }
 
-       store = SCDynamicStoreCreate(NULL, CFSTR("_SCNetworkInterfaceForceConfigurationRefresh"), NULL, NULL);
-       if (store == NULL) {
-               return FALSE;
-       }
-
        key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
                                                            kSCDynamicStoreDomainState,
                                                            ifName,
                                                            kSCEntNetRefreshConfiguration);
-       ok = SCDynamicStoreNotifyValue(store, key);
+       ok = SCDynamicStoreNotifyValue(NULL, key);
        CFRelease(key);
-       CFRelease(store);
        return ok;
 }
 
@@ -6422,12 +6480,14 @@ __SCNetworkInterfaceIsMember(SCPreferencesRef prefs, SCNetworkInterfaceRef inter
 
        members = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
 
+#if    !TARGET_OS_IPHONE
        // add Bond [member] interfaces
        interfaces = SCBondInterfaceCopyAll(prefs);
        if (interfaces != NULL) {
                __SCBondInterfaceListCollectMembers(interfaces, members);
                CFRelease(interfaces);
        }
+#endif // !TARGET_OS_IPHONE
 
        // add Bridge [member] interfaces
        interfaces = SCBridgeInterfaceCopyAll(prefs);
@@ -6530,3 +6590,141 @@ __SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterface
 
        return;
 }
+
+
+SCNetworkInterfaceRef
+_SCNetworkInterfaceCopyActive(SCDynamicStoreRef store, CFStringRef bsdName)
+{
+       SCNetworkInterfaceRef           interface;
+
+       interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeAllVirtualInterfaces);
+       if (interface == NULL) {
+               return NULL;
+       }
+
+       if (store != NULL) {
+               SCNetworkInterfacePrivateRef    interfacePrivate =
+                       (SCNetworkInterfacePrivateRef)interface;
+
+               CFRetain(store);
+               interfacePrivate->store = store;
+       }
+
+       return interface;
+}
+
+
+SCNetworkServicePrimaryRank
+SCNetworkInterfaceGetPrimaryRank(SCNetworkInterfaceRef interface)
+{
+       CFDictionaryRef                 entity;
+       SCNetworkInterfacePrivateRef    interfacePrivate =
+                                               (SCNetworkInterfacePrivateRef)interface;
+       CFStringRef                     ifName;
+       Boolean                         ok      = FALSE;
+       CFStringRef                     path;
+       SCNetworkServicePrimaryRank     rank    = kSCNetworkServicePrimaryRankDefault;
+       SCDynamicStoreRef               session;
+
+       ifName = SCNetworkInterfaceGetBSDName(interface);
+       if ((ifName == NULL) || (interfacePrivate->store == NULL)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return rank;
+       }
+
+       session = interfacePrivate->store;
+
+       path = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+                                                            kSCDynamicStoreDomainState,
+                                                            ifName,
+                                                            kSCEntNetService);
+       entity = SCDynamicStoreCopyValue(session, path);
+       CFRelease(path);
+
+       if (entity != NULL) {
+               if (isA_CFDictionary(entity)) {
+                       CFStringRef rankStr =
+                               CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
+                       ok = __str_to_rank(rankStr, &rank);
+               }
+               CFRelease(entity);
+       }
+
+       if (!ok) {
+               rank = kSCNetworkServicePrimaryRankDefault;
+               _SCErrorSet(kSCStatusInvalidArgument);
+       } else if (rank == kSCNetworkServicePrimaryRankDefault) {
+               _SCErrorSet(kSCStatusOK);
+       }
+
+       return (rank);
+}
+
+Boolean
+SCNetworkInterfaceSetPrimaryRank(SCNetworkInterfaceRef interface,
+                                SCNetworkServicePrimaryRank newRank)
+{
+       CFDictionaryRef                 entity;
+       SCNetworkInterfacePrivateRef    interfacePrivate =
+                                       (SCNetworkInterfacePrivateRef)interface;
+       CFStringRef                     ifName;
+       CFMutableDictionaryRef          newEntity;
+       Boolean                         ok              = TRUE;
+       CFStringRef                     path            = NULL;
+       CFStringRef                     rankStr;
+       SCDynamicStoreRef               session;
+
+       ifName = SCNetworkInterfaceGetBSDName(interface);
+       if ((ifName == NULL) || (interfacePrivate->store == NULL)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       session = interfacePrivate->store;
+
+       ok = __rank_to_str(newRank, &rankStr);
+       if (!ok) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       path = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+                                                            kSCDynamicStoreDomainState,
+                                                            ifName,
+                                                            kSCEntNetService);
+
+       entity = SCDynamicStoreCopyValue(session, path);
+       if (entity != NULL) {
+               if (!isA_CFDictionary(entity)) {
+                       CFRelease(entity);
+                       _SCErrorSet(kSCStatusFailed);
+                       goto done;
+               }
+               newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
+               CFRelease(entity);
+       } else {
+               newEntity = CFDictionaryCreateMutable(NULL,
+                                                     0,
+                                                     &kCFTypeDictionaryKeyCallBacks,
+                                                     &kCFTypeDictionaryValueCallBacks);
+       }
+
+       if (rankStr != NULL) {
+               CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
+       } else {
+               CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
+       }
+
+       if (CFDictionaryGetCount(newEntity) > 0) {
+               ok = SCDynamicStoreSetValue(session, path, newEntity);
+       } else {
+               ok = SCDynamicStoreRemoveValue(session, path);
+       }
+
+       CFRelease(newEntity);
+
+    done :
+
+       if (path != NULL)       CFRelease(path);
+       return ok;
+}
index 4b6ebd09aeccc651903cb3a6fa6680d7f02b0847..2d0c04f90266aec187f421114e5b51d06ebf50f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -24,6 +24,9 @@
 /*
  * Modification History
  *
+ * April 12, 2011              Allan Nathanson <ajn@apple.com>
+ * - add SCNetworkReachability "server"
+ *
  * March 31, 2004              Allan Nathanson <ajn@apple.com>
  * - use [SC] DNS configuration information
  *
@@ -35,6 +38,7 @@
 #include <TargetConditionals.h>
 #include <sys/cdefs.h>
 #include <dispatch/dispatch.h>
+#include <dispatch/private.h>
 #include <CoreFoundation/CoreFoundation.h>
 #include <CoreFoundation/CFRuntime.h>
 #include <SystemConfiguration/SystemConfiguration.h>
@@ -68,6 +72,8 @@
 #define s6_addr16 __u6_addr.__u6_addr16
 #endif
 
+#include "SCNetworkReachabilityInternal.h"
+
 #include <ppp/ppp_msg.h>
 
 #if    !TARGET_IPHONE_SIMULATOR
 
 
 
+#define        DEBUG_REACHABILITY_TYPE_NAME                    "create w/name"
+#define        DEBUG_REACHABILITY_TYPE_NAME_OPTIONS            "    + options"
+
+#define        DEBUG_REACHABILITY_TYPE_ADDRESS         "create w/address"
+#define        DEBUG_REACHABILITY_TYPE_ADDRESS_OPTIONS "       + options"
+
+#define        DEBUG_REACHABILITY_TYPE_ADDRESSPAIR             "create w/address pair"
+#define        DEBUG_REACHABILITY_TYPE_ADDRESSPAIR_OPTIONS     "            + options"
+
+
+static pthread_mutexattr_t     lock_attr;
+
+#define MUTEX_INIT(m) {                                                        \
+       int _lock_ = (pthread_mutex_init(m, &lock_attr) == 0);          \
+       assert(_lock_);                                                 \
+}
+
+#define        MUTEX_LOCK(m) {                                                 \
+       int _lock_ = (pthread_mutex_lock(m) == 0);                      \
+       assert(_lock_);                                                 \
+}
+
+#define        MUTEX_UNLOCK(m) {                                               \
+       int _unlock_ = (pthread_mutex_unlock(m) == 0);                  \
+       assert(_unlock_);                                               \
+}
+
+#define        MUTEX_ASSERT_HELD(m) {                                          \
+       int _locked_ = (pthread_mutex_lock(m) == EDEADLK);              \
+       assert(_locked_);                                               \
+}
+
+
 #ifdef HAVE_GETADDRINFO_INTERFACE_ASYNC_CALL
 /* Libinfo SPI */
 mach_port_t
@@ -100,33 +139,28 @@ _getaddrinfo_interface_async_call(const char                      *nodename,
 #endif /* HAVE_GETADDRINFO_INTERFACE_ASYNC_CALL */
 
 
-#define kSCNetworkReachabilityFlagsFirstResolvePending (1<<31)
+#define SCNETWORKREACHABILITY_TRIGGER_KEY      CFSTR("com.apple.SCNetworkReachability:FORCE-CHANGE")
 
 
-#define        N_QUICK 64
-
-
-typedef        enum { NO = 0, YES, UNKNOWN }   lazyBoolean;
+// how long (minimum time, us) to wait before retrying DNS query after EAI_NONAME
+#define EAI_NONAME_RETRY_DELAY_USEC    250000                  // 250ms
 
+// how long (maximum time, us) after DNS configuration change we accept EAI_NONAME
+// without question.
+#define EAI_NONAME_RETRY_LIMIT_USEC    2500000                 // 2.5s
 
-typedef enum {
-       reachabilityTypeAddress,
-       reachabilityTypeAddressPair,
-       reachabilityTypeName
-} addressType;
 
+// how long (maximum time, ns) to wait for a long-lived-query callback before
+// we assume EAI_NONAME.
+#define LLQ_TIMEOUT_NSEC               30 * NSEC_PER_SEC       // 30s
 
-// how long (minimum time, us) to wait before retrying DNS query after EAI_NONAME
-#define EAI_NONAME_RETRY_DELAY_USEC    250000
 
-// how long (maximum time, us) after DNS configuration change we accept EAI_NONAME
-// without question.
-#define EAI_NONAME_RETRY_LIMIT_USEC    2500000
+#define        N_QUICK 64
 
 
 static CFStringRef     __SCNetworkReachabilityCopyDescription  (CFTypeRef cf);
 static void            __SCNetworkReachabilityDeallocate       (CFTypeRef cf);
-static void            rlsPerform(void *info);
+static void            reachPerform                            (void *info);
 
 
 static Boolean
@@ -143,82 +177,6 @@ __SCNetworkReachabilityUnscheduleFromRunLoop       (SCNetworkReachabilityRef       target,
                                                 Boolean                        onDemand);
 
 
-typedef struct {
-       SCNetworkReachabilityFlags      flags;
-       unsigned int                    if_index;
-       Boolean                         sleeping;
-} ReachabilityInfo;
-
-
-typedef struct {
-
-       /* base CFType information */
-       CFRuntimeBase                   cfBase;
-
-       /* lock */
-       pthread_mutex_t                 lock;
-
-       /* address type */
-       addressType                     type;
-
-       /* target host name */
-       const char                      *name;
-       const char                      *serv;
-       struct addrinfo                 hints;
-       Boolean                         needResolve;
-       CFArrayRef                      resolvedAddress;        /* CFArray[CFData] */
-       int                             resolvedAddressError;
-
-       /* [scoped routing] interface constraints */
-       unsigned int                    if_index;
-       char                            if_name[IFNAMSIZ];
-
-       /* local & remote addresses */
-       struct sockaddr                 *localAddress;
-       struct sockaddr                 *remoteAddress;
-
-       /* current reachability flags */
-       ReachabilityInfo                info;
-       ReachabilityInfo                last_notify;
-
-       /* run loop source, callout, context, rl scheduling info */
-       Boolean                         scheduled;
-       CFRunLoopSourceRef              rls;
-       SCNetworkReachabilityCallBack   rlsFunction;
-       SCNetworkReachabilityContext    rlsContext;
-       CFMutableArrayRef               rlList;
-
-       dispatch_queue_t                dispatchQueue;          // SCNetworkReachabilitySetDispatchQueue
-       dispatch_queue_t                asyncDNSQueue;
-       dispatch_source_t               asyncDNSSource;
-
-       /* [async] DNS query info */
-       Boolean                         haveDNS;
-       mach_port_t                     dnsMP;
-       CFMachPortRef                   dnsPort;
-       CFRunLoopSourceRef              dnsRLS;
-       struct timeval                  dnsQueryStart;
-       struct timeval                  dnsQueryEnd;
-       dispatch_source_t               dnsRetry;               // != NULL if DNS retry request queued
-       int                             dnsRetryCount;          // number of retry attempts
-
-       /* [async] processing info */
-       struct timeval                  last_dns;
-
-       /* on demand info */
-       Boolean                         onDemandBypass;
-       CFStringRef                     onDemandName;
-       CFStringRef                     onDemandRemoteAddress;
-       SCNetworkReachabilityRef        onDemandServer;
-       CFStringRef                     onDemandServiceID;
-
-
-       /* logging */
-       char                            log_prefix[32];
-
-} SCNetworkReachabilityPrivate, *SCNetworkReachabilityPrivateRef;
-
-
 static CFTypeID __kSCNetworkReachabilityTypeID = _kCFRuntimeNotATypeID;
 
 
@@ -236,14 +194,34 @@ static const CFRuntimeClass __SCNetworkReachabilityClass = {
 
 
 static pthread_once_t          initialized     = PTHREAD_ONCE_INIT;
-static const ReachabilityInfo  NOT_REACHABLE   = { 0,          0,      FALSE };
-static const ReachabilityInfo  NOT_REPORTED    = { 0xFFFFFFFF, 0,      FALSE };
+static const ReachabilityInfo  NOT_REACHABLE   = { 0, 0,               0, { 0 }, FALSE };
+static const ReachabilityInfo  NOT_REPORTED    = { 0, 0xFFFFFFFF,      0, { 0 }, FALSE };
 static int                     rtm_seq         = 0;
 
 
+static const struct addrinfo   HINTS_DEFAULT   = {
+#ifdef AI_PARALLEL
+       .ai_flags       = AI_ADDRCONFIG | AI_PARALLEL,
+#else  // AI_PARALLEL
+       .ai_flags       = AI_ADDRCONFIG,
+#endif // AI_PARALLEL
+};
+
+
 static const struct timeval    TIME_ZERO       = { 0, 0 };
 
 
+static Boolean                 D_llqBypass     = FALSE;
+static int                     llqCount        = 0;
+static DNSServiceRef           llqMain         = NULL;
+static CFMutableSetRef         llqUpdated      = NULL;
+
+
+#ifdef HAVE_REACHABILITY_SERVER
+static Boolean                 D_serverBypass  = FALSE;
+#endif // HAVE_REACHABILITY_SERVER
+
+
 #if    !TARGET_OS_IPHONE
 /*
  * Power capabilities (sleep/wake)
@@ -256,7 +234,6 @@ static IOPMSystemPowerStateCapabilities     power_capabilities      = kIOPMSytemPowerStat
  * host "something has changed" notifications
  */
 
-static pthread_mutex_t         hn_lock         = PTHREAD_MUTEX_INITIALIZER;
 static SCDynamicStoreRef       hn_store        = NULL;
 static dispatch_queue_t                hn_dispatchQueue = NULL;
 static CFMutableSetRef         hn_targets      = NULL;
@@ -278,11 +255,11 @@ static int                        dns_token;
 static Boolean                 dns_token_valid         = FALSE;
 
 
-static __inline__ CFTypeRef
-isA_SCNetworkReachability(CFTypeRef obj)
-{
-       return (isA_CFType(obj, SCNetworkReachabilityGetTypeID()));
-}
+typedef enum {
+       dns_query_sync,
+       dns_query_async,
+       dns_query_llq
+} dns_query_type;
 
 
 static void
@@ -299,62 +276,106 @@ __dns_query_start(struct timeval *dnsQueryStart,
 static void
 __dns_query_end(SCNetworkReachabilityRef       target,
                Boolean                         found,
-               Boolean                         async,
+               dns_query_type                  query_type,
                struct timeval                  *dnsQueryStart,
                struct timeval                  *dnsQueryEnd)
 {
        struct timeval                  dnsQueryElapsed;
+       Boolean                         firstQuery;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
+       // report initial or updated query time
+       firstQuery = !timerisset(dnsQueryEnd);
+
        (void) gettimeofday(dnsQueryEnd, NULL);
 
        if (!_sc_debug) {
                return;
        }
 
-       if (dnsQueryStart->tv_sec == 0) {
+       if (!timerisset(dnsQueryStart)) {
                return;
        }
 
        timersub(dnsQueryEnd, dnsQueryStart, &dnsQueryElapsed);
-       SCLog(TRUE, LOG_INFO,
-             CFSTR("%s%ssync DNS complete%s (query time = %d.%3.3d)"),
-             targetPrivate->log_prefix,
-             async ? "a" : "",
-             found ? "" : ", host not found",
-             dnsQueryElapsed.tv_sec,
-             dnsQueryElapsed.tv_usec / 1000);
+       switch (query_type) {
+
+//             #define QUERY_TIME__FMT "%d.%3.3d"
+//             #define QUERY_TIME__DIV 1000
+
+               #define QUERY_TIME__FMT "%d.%6.6d"
+               #define QUERY_TIME__DIV 1
+
+               case dns_query_sync :
+                       SCLog(TRUE, LOG_INFO,
+                             CFSTR("%ssync DNS complete%s (query time = " QUERY_TIME__FMT ")"),
+                             targetPrivate->log_prefix,
+                             found ? "" : ", host not found",
+                             dnsQueryElapsed.tv_sec,
+                             dnsQueryElapsed.tv_usec / QUERY_TIME__DIV);
+                       break;
+               case dns_query_async :
+                       SCLog(TRUE, LOG_INFO,
+                             CFSTR("%sasync DNS complete%s (query time = " QUERY_TIME__FMT ")"),
+                             targetPrivate->log_prefix,
+                             found ? "" : ", host not found",
+                             dnsQueryElapsed.tv_sec,
+                             dnsQueryElapsed.tv_usec / QUERY_TIME__DIV);
+                       break;
+               case dns_query_llq :
+                       SCLog(TRUE, LOG_INFO,
+                             CFSTR("%sDNS updated%s (%s = " QUERY_TIME__FMT ")"),
+                             targetPrivate->log_prefix,
+                             found ? "" : ", host not found",
+                             firstQuery ? "query time" : "updated after",
+                             dnsQueryElapsed.tv_sec,
+                             dnsQueryElapsed.tv_usec / QUERY_TIME__DIV);
+                       break;
+       }
 
        return;
 }
 
 
 static __inline__ Boolean
-__reach_equal(ReachabilityInfo *r1, ReachabilityInfo *r2)
+__reach_changed(ReachabilityInfo *r1, ReachabilityInfo *r2)
 {
        if (r1->flags != r2->flags) {
                // if the reachability flags changed
-               return FALSE;
+               return TRUE;
        }
 
        if (r1->if_index != r2->if_index) {
                // if the target interface changed
-               return FALSE;
+               return TRUE;
        }
 
        if ((r1->sleeping != r2->sleeping) && !r2->sleeping) {
                // if our sleep/wake status changed and if we
                // are no longer sleeping
-               return FALSE;
+               return TRUE;
        }
 
-       return TRUE;
+       return FALSE;
+}
+
+
+static __inline__ void
+_reach_set(ReachabilityInfo *dst, const ReachabilityInfo *src, uint64_t cycle)
+{
+       memcpy(dst, src, sizeof(ReachabilityInfo));
+       dst->cycle = cycle;
+
+       return;
 }
 
 
+#pragma mark -
+#pragma mark SCDynamicStore info
+
+
 typedef struct {
        SCDynamicStoreRef       store;
-       Boolean                 storeAdded;
        CFStringRef             entity;
        CFDictionaryRef         dict;
        CFIndex                 n;
@@ -365,66 +386,132 @@ typedef struct {
 } ReachabilityStoreInfo, *ReachabilityStoreInfoRef;
 
 
+static ReachabilityStoreInfo   S_storeInfo             = { 0 };
+static Boolean                 S_storeInfoActive       = FALSE;
+
+
+static dispatch_queue_t
+_storeInfo_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create("SCNetworkReachabilty.storeInfo", NULL);
+       });
+
+       return q;
+}
+
+
 static void
-initReachabilityStoreInfo(ReachabilityStoreInfoRef store_info)
+ReachabilityStoreInfo_copy(ReachabilityStoreInfoRef    src,
+                          ReachabilityStoreInfoRef     dst)
 {
-       bzero(store_info, sizeof(ReachabilityStoreInfo));
+       if (src->dict != NULL) {
+               dst->store = src->store;
+               CFRetain(dst->store);
+
+               dst->dict = src->dict;
+               CFRetain(dst->dict);
+
+               dst->n = src->n;
+               if (dst->n > 0) {
+                       if (dst->n <= (CFIndex)(sizeof(dst->keys_q) / sizeof(CFTypeRef))) {
+                               dst->keys   = dst->keys_q;
+                               dst->values = dst->values_q;
+                       } else {
+                               dst->keys   = CFAllocatorAllocate(NULL, dst->n * sizeof(CFTypeRef), 0);
+                               dst->values = CFAllocatorAllocate(NULL, dst->n * sizeof(CFTypeRef), 0);
+                       }
+                       memcpy(dst->keys,   src->keys,   dst->n * sizeof(CFTypeRef));
+                       memcpy(dst->values, src->values, dst->n * sizeof(CFTypeRef));
+               }
+       }
+
        return;
 }
 
 
-static Boolean
-updateReachabilityStoreInfo(ReachabilityStoreInfoRef   store_info,
-                           SCDynamicStoreRef           *storeP,
-                           sa_family_t                 sa_family)
+static void
+ReachabilityStoreInfo_enable(Boolean enable)
 {
-       CFStringRef             pattern;
-       CFMutableArrayRef       patterns;
+       dispatch_sync(_storeInfo_queue(), ^{
+               S_storeInfoActive = enable;
+       });
 
-       switch (sa_family) {
-               case AF_UNSPEC :
-                       store_info->entity = NULL;
-                       break;
-               case AF_INET :
-                       store_info->entity = kSCEntNetIPv4;
-                       break;
-               case AF_INET6 :
-                       store_info->entity = kSCEntNetIPv6;
-                       break;
-               default :
-                       return FALSE;
+       return;
+}
+
+
+static void
+ReachabilityStoreInfo_free(ReachabilityStoreInfoRef store_info)
+{
+       if ((store_info->n > 0) && (store_info->keys != store_info->keys_q)) {
+               CFAllocatorDeallocate(NULL, store_info->keys);
+               store_info->keys = NULL;
+
+               CFAllocatorDeallocate(NULL, store_info->values);
+               store_info->values = NULL;
        }
+       store_info->n = 0;
 
        if (store_info->dict != NULL) {
-               // if info already available
-               return TRUE;
+               CFRelease(store_info->dict);
+               store_info->dict = NULL;
        }
 
-       if (store_info->store == NULL) {
-               store_info->store = (storeP != NULL) ? *storeP : NULL;
-               if (store_info->store == NULL) {
-                       store_info->store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkReachability"), NULL, NULL);
-                       if (store_info->store == NULL) {
-                               SCLog(TRUE, LOG_ERR, CFSTR("updateReachabilityStoreInfo SCDynamicStoreCreate() failed"));
-                               return FALSE;
-                       }
+       if (store_info->store != NULL) {
+               CFRelease(store_info->store);
+               store_info->store = NULL;
+       }
 
-                       if (storeP != NULL) {
-                               /// pass back the allocated SCDynamicStoreRef
-                               *storeP = store_info->store;
-                       } else {
-                               // this one is ours
-                               store_info->storeAdded = TRUE;
+       return;
+}
+
+
+static void
+ReachabilityStoreInfo_init(ReachabilityStoreInfoRef store_info)
+{
+       dispatch_sync(_storeInfo_queue(), ^{
+               bzero(store_info, sizeof(ReachabilityStoreInfo));
+
+               if (S_storeInfoActive && (S_storeInfo.dict != NULL)) {
+                       ReachabilityStoreInfo_copy(&S_storeInfo, store_info);
+               }
+       });
+
+       return;
+}
+
+
+static void
+ReachabilityStoreInfo_save(ReachabilityStoreInfoRef store_info)
+{
+       dispatch_sync(_storeInfo_queue(), ^{
+               if ((store_info == NULL) ||
+                   !_SC_CFEqual(store_info->dict, S_storeInfo.dict)) {
+                       // free any old info
+                       ReachabilityStoreInfo_free(&S_storeInfo);
+
+                       // save new info
+                       if (S_storeInfoActive &&
+                           (store_info != NULL) &&
+                           (store_info->dict != NULL)) {
+                               ReachabilityStoreInfo_copy(store_info, &S_storeInfo);
                        }
                }
-       }
+       });
 
-       if (sa_family == AF_UNSPEC) {
-               // if the address family was not specified than
-               // all we wanted, for now, was to establish the
-               // SCDynamicStore session
-               return TRUE;
-       }
+       return;
+}
+
+
+static Boolean
+ReachabilityStoreInfo_fill(ReachabilityStoreInfoRef store_info)
+{
+       CFStringRef             pattern;
+       CFMutableArrayRef       patterns;
 
        patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
 
@@ -535,31 +622,98 @@ updateReachabilityStoreInfo(ReachabilityStoreInfoRef      store_info,
 }
 
 
-static void
-freeReachabilityStoreInfo(ReachabilityStoreInfoRef store_info)
+static Boolean
+ReachabilityStoreInfo_update(ReachabilityStoreInfoRef  store_info,
+                            SCDynamicStoreRef          *storeP,
+                            sa_family_t                sa_family)
 {
-       if ((store_info->n > 0) && (store_info->keys != store_info->keys_q)) {
-               CFAllocatorDeallocate(NULL, store_info->keys);
-               store_info->keys = NULL;
+       __block Boolean         ok      = TRUE;
 
-               CFAllocatorDeallocate(NULL, store_info->values);
-               store_info->values = NULL;
+       switch (sa_family) {
+               case AF_UNSPEC :
+                       store_info->entity = NULL;
+                       break;
+               case AF_INET :
+                       store_info->entity = kSCEntNetIPv4;
+                       break;
+               case AF_INET6 :
+                       store_info->entity = kSCEntNetIPv6;
+                       break;
+               default :
+                       return FALSE;
        }
 
        if (store_info->dict != NULL) {
-               CFRelease(store_info->dict);
-               store_info->dict = NULL;
+               // if info already available
+               return TRUE;
        }
 
-       if (store_info->storeAdded && (store_info->store != NULL)) {
-               CFRelease(store_info->store);
-               store_info->store = NULL;
-       }
+       dispatch_sync(_storeInfo_queue(), ^{
+               if (S_storeInfoActive && (S_storeInfo.dict != NULL)) {
+                       // free any info
+                       ReachabilityStoreInfo_free(store_info);
 
-       return;
+                       // copy the shared/available info
+                       ReachabilityStoreInfo_copy(&S_storeInfo, store_info);
+               }
+
+               if (store_info->store == NULL) {
+                       store_info->store = (storeP != NULL) ? *storeP : NULL;
+                       if (store_info->store != NULL) {
+                               // keep a reference to the passed in SCDynamicStore
+                               CFRetain(store_info->store);
+                       } else {
+                               store_info->store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkReachability"), NULL, NULL);
+                               if (store_info->store == NULL) {
+                                       SCLog(TRUE, LOG_ERR, CFSTR("ReachabilityStoreInfo_update SCDynamicStoreCreate() failed"));
+                                       return;
+                               }
+
+                               if (storeP != NULL) {
+                                       // and pass back a reference
+                                       *storeP = store_info->store;
+                                       CFRetain(*storeP);
+                               }
+                       }
+               }
+
+               if (sa_family == AF_UNSPEC) {
+                       // if the address family was not specified than
+                       // all we wanted, for now, was to establish the
+                       // SCDynamicStore session
+                       return;
+               }
+
+               if (store_info->dict != NULL) {
+                       // or we have picked up the shared info
+                       return;
+               }
+
+               ok = ReachabilityStoreInfo_fill(store_info);
+               if (!ok) {
+                       return;
+               }
+
+               if (!_SC_CFEqual(store_info->dict, S_storeInfo.dict)) {
+                       // free any old info
+                       ReachabilityStoreInfo_free(&S_storeInfo);
+
+                       // save new info
+                       if (S_storeInfoActive &&
+                           (store_info->dict != NULL)) {
+                               ReachabilityStoreInfo_copy(store_info, &S_storeInfo);
+                       }
+               }
+       });
+
+       return ok;
 }
 
 
+#pragma mark -
+#pragma mark PPP info
+
+
 static int
 updatePPPStatus(ReachabilityStoreInfoRef       store_info,
                const struct sockaddr           *sa,
@@ -572,7 +726,7 @@ updatePPPStatus(ReachabilityStoreInfoRef    store_info,
        CFStringRef     ppp_if;
        int             sc_status       = kSCStatusNoKey;
 
-       if (!updateReachabilityStoreInfo(store_info, NULL, sa->sa_family)) {
+       if (!ReachabilityStoreInfo_update(store_info, NULL, sa->sa_family)) {
                return kSCStatusReachabilityUnknown;
        }
 
@@ -727,7 +881,7 @@ updatePPPAvailable(ReachabilityStoreInfoRef store_info,
        CFIndex         i;
        int             sc_status       = kSCStatusNoKey;
 
-       if (!updateReachabilityStoreInfo(store_info,
+       if (!ReachabilityStoreInfo_update(store_info,
                                         NULL,
                                         (sa != NULL) ? sa->sa_family : AF_INET)) {
                return kSCStatusReachabilityUnknown;
@@ -830,6 +984,10 @@ updatePPPAvailable(ReachabilityStoreInfoRef        store_info,
 }
 
 
+#pragma mark -
+#pragma mark VPN info
+
+
 #if    !TARGET_IPHONE_SIMULATOR
 static int
 updateVPNStatus(ReachabilityStoreInfoRef       store_info,
@@ -843,7 +1001,7 @@ updateVPNStatus(ReachabilityStoreInfoRef   store_info,
        CFStringRef     vpn_if;
        int             sc_status       = kSCStatusNoKey;
 
-       if (!updateReachabilityStoreInfo(store_info, NULL, sa->sa_family)) {
+       if (!ReachabilityStoreInfo_update(store_info, NULL, sa->sa_family)) {
                return kSCStatusReachabilityUnknown;
        }
 
@@ -971,7 +1129,7 @@ updateVPNAvailable(ReachabilityStoreInfoRef        store_info,
        CFIndex         i;
        int             sc_status       = kSCStatusNoKey;
 
-       if (!updateReachabilityStoreInfo(store_info,
+       if (!ReachabilityStoreInfo_update(store_info,
                                         NULL,
                                         (sa != NULL) ? sa->sa_family : AF_INET)) {
                return kSCStatusReachabilityUnknown;
@@ -1061,6 +1219,10 @@ updateVPNAvailable(ReachabilityStoreInfoRef      store_info,
 #endif // !TARGET_IPHONE_SIMULATOR
 
 
+#pragma mark -
+#pragma mark IPSec info
+
+
 static int
 updateIPSecStatus(ReachabilityStoreInfoRef     store_info,
                  const struct sockaddr         *sa,
@@ -1073,7 +1235,7 @@ updateIPSecStatus(ReachabilityStoreInfoRef        store_info,
        CFStringRef     ipsec_if;
        int             sc_status       = kSCStatusNoKey;
 
-       if (!updateReachabilityStoreInfo(store_info, NULL, sa->sa_family)) {
+       if (!ReachabilityStoreInfo_update(store_info, NULL, sa->sa_family)) {
                return kSCStatusReachabilityUnknown;
        }
 
@@ -1192,6 +1354,10 @@ updateIPSecStatus(ReachabilityStoreInfoRef       store_info,
 
 
 
+#pragma mark -
+#pragma mark Reachability engine
+
+
 #define ROUNDUP(a, size) \
        (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
 
@@ -1219,7 +1385,10 @@ get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
 
 
 typedef struct {
-       char                    buf[BUFLEN];
+       union {
+               char                    bytes[BUFLEN];
+               struct rt_msghdr        rtm;
+       } buf;
        int                     error;
        struct sockaddr         *rti_info[RTAX_MAX];
        struct rt_msghdr        *rtm;
@@ -1251,7 +1420,7 @@ route_get(const struct sockaddr   *address,
 
        bzero(info, sizeof(*info));
 
-       info->rtm = (struct rt_msghdr *)&info->buf;
+       info->rtm = &info->buf.rtm;
        info->rtm->rtm_msglen  = sizeof(struct rt_msghdr);
        info->rtm->rtm_version = RTM_VERSION;
 #ifdef RTM_GET_SILENT
@@ -1273,7 +1442,8 @@ route_get(const struct sockaddr   *address,
                case AF_INET6: {
                        struct sockaddr_in6     *sin6;
 
-                       sin6 = (struct sockaddr_in6 *)address;
+                       /* ALIGN: caller ensures that the address is aligned */
+                       sin6 = (struct sockaddr_in6 *)(void *)address;
                        if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
                             IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) &&
                            (sin6->sin6_scope_id != 0)) {
@@ -1352,7 +1522,7 @@ route_get(const struct sockaddr   *address,
        while (TRUE) {
                int     n;
 
-               n = read(rsock, (void *)&info->buf, sizeof(info->buf));
+               n = read(rsock, &info->buf, sizeof(info->buf));
                if (n == -1) {
                        int     error   = errno;
 
@@ -1411,7 +1581,8 @@ route_get(const struct sockaddr   *address,
                return EINVAL;
        }
 
-       info->sdl = (struct sockaddr_dl *) info->rti_info[RTAX_IFP];
+       /* ALIGN: accessors are retrieving byte values, cast ok. */
+       info->sdl = (struct sockaddr_dl *)(void *) info->rti_info[RTAX_IFP];
        if ((info->sdl->sdl_nlen == 0) || (info->sdl->sdl_nlen > IFNAMSIZ)) {
                /* no interface name */
                return EHOSTUNREACH;
@@ -1438,7 +1609,7 @@ checkAddress(ReachabilityStoreInfoRef     store_info,
        char                    *statusMessage  = NULL;
        struct sockaddr_in      v4mapped;
 
-       *reach_info = NOT_REACHABLE;
+       _reach_set(reach_info, &NOT_REACHABLE, reach_info->cycle);
 
        if (address == NULL) {
                /* special case: check only for available paths off the system */
@@ -1479,7 +1650,8 @@ checkAddress(ReachabilityStoreInfoRef     store_info,
        }
 
        if (address->sa_family == AF_INET6) {
-               struct sockaddr_in6     *sin6   = (struct sockaddr_in6 *)address;
+               /* ALIGN: sin6_addr accessed aligned, cast ok. */
+               struct sockaddr_in6     *sin6   = (struct sockaddr_in6 *)(void *)address;
 
                if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
                        bzero(&v4mapped, sizeof(v4mapped));
@@ -1552,21 +1724,24 @@ checkAddress(ReachabilityStoreInfoRef   store_info,
 
                switch (address->sa_family) {
                        case AF_INET :
-                               addr1 = &((struct sockaddr_in *)address)->sin_addr;
-                               addr2 = &((struct sockaddr_in *)info.rti_info[RTAX_IFA])->sin_addr;
+                               /* ALIGN: cast ok, because only bcmp is used. */
+                               addr1 = &((struct sockaddr_in *)(void *)address)->sin_addr;
+                               addr2 = &((struct sockaddr_in *)(void *)info.rti_info[RTAX_IFA])->sin_addr;
                                len = sizeof(struct in_addr);
 
                                /*
                                 * check if 0.0.0.0
                                 */
-                               if (((struct sockaddr_in *)address)->sin_addr.s_addr == 0) {
+                               /* ALIGN: sin_addr should be aligned, cast ok. */
+                               if (((struct sockaddr_in *)(void *)address)->sin_addr.s_addr == 0) {
                                        statusMessage = "isReachable (this host)";
                                        reach_info->flags |= kSCNetworkReachabilityFlagsIsLocalAddress;
                                }
                                break;
                        case AF_INET6 :
-                               addr1 = &((struct sockaddr_in6 *)address)->sin6_addr;
-                               addr2 = &((struct sockaddr_in6 *)info.rti_info[RTAX_IFA])->sin6_addr;
+                                /* ALIGN: cast ok, because only bcmp is used. */
+                               addr1 = &((struct sockaddr_in6 *)(void *)address)->sin6_addr;
+                               addr2 = &((struct sockaddr_in6 *)(void *)info.rti_info[RTAX_IFA])->sin6_addr;
                                len = sizeof(struct in6_addr);
                                break;
                        default :
@@ -1591,6 +1766,7 @@ checkAddress(ReachabilityStoreInfoRef     store_info,
              if_name,
              (info.sdl->sdl_nlen <= IFNAMSIZ) ? info.sdl->sdl_nlen : IFNAMSIZ);
 
+       strlcpy(reach_info->if_name, if_name, sizeof(reach_info->if_name));
        reach_info->if_index = info.sdl->sdl_index;
 
        if (_sc_debug) {
@@ -1671,15 +1847,21 @@ checkAddress(ReachabilityStoreInfoRef   store_info,
 #pragma mark SCNetworkReachability APIs
 
 
-static CFStringRef
-__SCNetworkReachabilityCopyDescription(CFTypeRef cf)
+static __inline__ CFTypeRef
+isA_SCNetworkReachability(CFTypeRef obj)
 {
-       CFAllocatorRef                  allocator       = CFGetAllocator(cf);
-       CFMutableStringRef              result;
-       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)cf;
+       return (isA_CFType(obj, SCNetworkReachabilityGetTypeID()));
+}
 
-       result = CFStringCreateMutable(allocator, 0);
-       CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkReachability %p [%p]> {"), cf, allocator);
+
+CFStringRef
+_SCNetworkReachabilityCopyTargetDescription(SCNetworkReachabilityRef target)
+{
+       CFAllocatorRef                  allocator       = CFGetAllocator(target);
+       CFMutableStringRef              str;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       str = CFStringCreateMutable(allocator, 0);
        switch (targetPrivate->type) {
                case reachabilityTypeAddress :
                case reachabilityTypeAddressPair : {
@@ -1687,13 +1869,13 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
 
                        if (targetPrivate->localAddress != NULL) {
                                _SC_sockaddr_to_string(targetPrivate->localAddress, buf, sizeof(buf));
-                               CFStringAppendFormat(result, NULL, CFSTR("local address = %s"),
+                               CFStringAppendFormat(str, NULL, CFSTR("local address = %s"),
                                                     buf);
                        }
 
                        if (targetPrivate->remoteAddress != NULL) {
                                _SC_sockaddr_to_string(targetPrivate->remoteAddress, buf, sizeof(buf));
-                               CFStringAppendFormat(result, NULL, CFSTR("%s%saddress = %s"),
+                               CFStringAppendFormat(str, NULL, CFSTR("%s%saddress = %s"),
                                                     targetPrivate->localAddress ? ", " : "",
                                                     (targetPrivate->type == reachabilityTypeAddressPair) ? "remote " : "",
                                                     buf);
@@ -1702,53 +1884,107 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
                }
                case reachabilityTypeName : {
                        if ((targetPrivate->name != NULL)) {
-                               CFStringAppendFormat(result, NULL, CFSTR("name = %s"), targetPrivate->name);
+                               CFStringAppendFormat(str, NULL, CFSTR("name = %s"), targetPrivate->name);
                        }
                        if ((targetPrivate->serv != NULL)) {
-                               CFStringAppendFormat(result, NULL, CFSTR("%sserv = %s"),
+                               CFStringAppendFormat(str, NULL, CFSTR("%sserv = %s"),
                                                     targetPrivate->name != NULL ? ", " : "",
                                                     targetPrivate->serv);
                        }
-                       if ((targetPrivate->resolvedAddress != NULL) || (targetPrivate->resolvedAddressError != NETDB_SUCCESS)) {
-                               if (targetPrivate->resolvedAddress != NULL) {
-                                       if (isA_CFArray(targetPrivate->resolvedAddress)) {
-                                               CFIndex i;
-                                               CFIndex n       = CFArrayGetCount(targetPrivate->resolvedAddress);
-
-                                               CFStringAppendFormat(result, NULL, CFSTR(" ("));
-                                               for (i = 0; i < n; i++) {
-                                                       CFDataRef       address;
-                                                       char            buf[64];
-                                                       struct sockaddr *sa;
-
-                                                       address = CFArrayGetValueAtIndex(targetPrivate->resolvedAddress, i);
-                                                       sa      = (struct sockaddr *)CFDataGetBytePtr(address);
-                                                       _SC_sockaddr_to_string(sa, buf, sizeof(buf));
-                                                       CFStringAppendFormat(result, NULL, CFSTR("%s%s"),
-                                                                            i > 0 ? ", " : "",
-                                                                            buf);
-                                               }
-                                               CFStringAppendFormat(result, NULL, CFSTR(")"));
-                                       } else {
-                                               CFStringAppendFormat(result, NULL, CFSTR(" (no addresses)"));
+                       break;
+               }
+       }
+
+       return str;
+}
+
+
+CFStringRef
+_SCNetworkReachabilityCopyTargetFlags(SCNetworkReachabilityRef target)
+{
+       CFAllocatorRef                  allocator       = CFGetAllocator(target);
+       CFStringRef                     str;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       str = CFStringCreateWithFormat(allocator,
+                                      NULL,
+                                      CFSTR("flags = 0x%08x, if_index = %hu%s"),
+                                      targetPrivate->info.flags,
+                                      targetPrivate->info.if_index,
+                                      targetPrivate->info.sleeping ? ", z" : "");
+       return str;
+}
+
+
+static CFStringRef
+__SCNetworkReachabilityCopyDescription(CFTypeRef cf)
+{
+       CFAllocatorRef                  allocator       = CFGetAllocator(cf);
+       CFMutableStringRef              result;
+       CFStringRef                     str;
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)cf;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       result = CFStringCreateMutable(allocator, 0);
+       CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkReachability %p [%p]> {"), cf, allocator);
+
+       // add target description
+       str = _SCNetworkReachabilityCopyTargetDescription(target);
+       CFStringAppend(result, str);
+       CFRelease(str);
+
+       // add additional "name" info
+       if (targetPrivate->type == reachabilityTypeName) {
+               if (targetPrivate->dnsMP != MACH_PORT_NULL) {
+                       CFStringAppendFormat(result, NULL, CFSTR(" (DNS query active)"));
+               } else if (targetPrivate->dnsRetry != NULL) {
+                       CFStringAppendFormat(result, NULL, CFSTR(" (DNS retry queued)"));
+               } else if ((targetPrivate->resolvedAddress != NULL) || (targetPrivate->resolvedAddressError != NETDB_SUCCESS)) {
+                       if (targetPrivate->resolvedAddress != NULL) {
+                               if (isA_CFArray(targetPrivate->resolvedAddress)) {
+                                       CFIndex i;
+                                       CFIndex n       = CFArrayGetCount(targetPrivate->resolvedAddress);
+
+                                       CFStringAppendFormat(result, NULL, CFSTR(" ("));
+                                       for (i = 0; i < n; i++) {
+                                               CFDataRef       address;
+                                               char            buf[64];
+                                               struct sockaddr *sa;
+
+                                               address = CFArrayGetValueAtIndex(targetPrivate->resolvedAddress, i);
+                                               sa      = (struct sockaddr *)CFDataGetBytePtr(address);
+                                               _SC_sockaddr_to_string(sa, buf, sizeof(buf));
+                                               CFStringAppendFormat(result, NULL, CFSTR("%s%s"),
+                                                                    i > 0 ? ", " : "",
+                                                                    buf);
                                        }
-                               } else {
-                                       CFStringAppendFormat(result, NULL, CFSTR(" (%s)"),
+                               } else if (CFEqual(targetPrivate->resolvedAddress, kCFNull)) {
+                                       CFStringAppendFormat(result, NULL, CFSTR(" (%s"),
                                                             gai_strerror(targetPrivate->resolvedAddressError));
+                               } else {
+                                       CFStringAppendFormat(result, NULL, CFSTR(" (no addresses"));
                                }
-                       } else if (targetPrivate->dnsPort != NULL) {
-                               CFStringAppendFormat(result, NULL, CFSTR(" (DNS query active)"));
+                       } else {
+                               CFStringAppendFormat(result, NULL, CFSTR(" (%s"),
+                                                    gai_strerror(targetPrivate->resolvedAddressError));
                        }
-                       break;
+                       if (targetPrivate->llqActive) {
+                               CFStringAppendFormat(result, NULL, CFSTR("), DNS llq active"));
+                       } else {
+                               CFStringAppendFormat(result, NULL, CFSTR(")"));
+                       }
+               } else if (targetPrivate->llqActive) {
+                       CFStringAppendFormat(result, NULL, CFSTR(" (DNS llq active)"));
                }
        }
+
+       // add flags
        if (targetPrivate->scheduled) {
-               CFStringAppendFormat(result,
-                                    NULL,
-                                    CFSTR(", flags = 0x%08x, if_index = %hu"),
-                                    targetPrivate->info.flags,
-                                    targetPrivate->info.if_index);
+               str = _SCNetworkReachabilityCopyTargetFlags(target);
+               CFStringAppendFormat(result, NULL, CFSTR(", %@"), str);
+               CFRelease(str);
        }
+
        CFStringAppendFormat(result, NULL, CFSTR("}"));
 
        return result;
@@ -1758,11 +1994,20 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf)
 static void
 __SCNetworkReachabilityDeallocate(CFTypeRef cf)
 {
-       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)cf;
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)cf;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
        SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%srelease"),
              targetPrivate->log_prefix);
 
+#ifdef HAVE_REACHABILITY_SERVER
+       /* disconnect from the reachability server */
+
+       if (targetPrivate->serverActive) {
+               __SCNetworkReachabilityServer_targetRemove(target);
+       }
+#endif // HAVE_REACHABILITY_SERVER
+
        /* release resources */
 
        pthread_mutex_destroy(&targetPrivate->lock);
@@ -1802,6 +2047,24 @@ __SCNetworkReachabilityDeallocate(CFTypeRef cf)
                CFRelease(targetPrivate->onDemandServiceID);
        }
 
+#ifdef HAVE_REACHABILITY_SERVER
+       if (targetPrivate->serverDigest != NULL) {
+               CFRelease(targetPrivate->serverDigest);
+       }
+
+       if (targetPrivate->serverGroup != NULL) {
+               dispatch_release(targetPrivate->serverGroup);
+       }
+
+       if (targetPrivate->serverQueue != NULL) {
+               dispatch_release(targetPrivate->serverQueue);
+       }
+
+       if (targetPrivate->serverWatchers != NULL) {
+               CFRelease(targetPrivate->serverWatchers);
+       }
+#endif // HAVE_REACHABILITY_SERVER
+
        return;
 }
 
@@ -1817,24 +2080,57 @@ __SCNetworkReachabilityInitialize(void)
                _sc_debug = TRUE;
        }
 
+       // set per-process "bypass" of the SCNetworkReachability server
+       if (getenv("LONG_LIVED_QUERY_BYPASS") != NULL) {
+               D_llqBypass = TRUE;
+       }
+
+#ifdef HAVE_REACHABILITY_SERVER
+       // set per-process "bypass" of the SCNetworkReachability server
+       if (getenv("REACH_SERVER_BYPASS") != NULL) {
+               D_serverBypass = TRUE;
+       }
+#endif // HAVE_REACHABILITY_SERVER
+
+       pthread_mutexattr_init(&lock_attr);
+       pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_ERRORCHECK);
+
        return;
 }
 
 
+__private_extern__
+dispatch_queue_t
+__SCNetworkReachability_concurrent_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create("SCNetworkReachabilty.concurrent",
+                                         DISPATCH_QUEUE_CONCURRENT);
+               dispatch_queue_set_width(q, 32);
+       });
+
+       return q;
+}
+
+
 /*
- * __SCNetworkReachabilityPerformInline
+ * __SCNetworkReachabilityPerformInlineNoLock
  *
- * Calls rlsPerform()
+ * Calls reachPerform()
  * - caller must be holding a reference to the target
  * - caller must *not* be holding the target lock
+ * - caller must be running on the __SCNetworkReachability_concurrent_queue()
  */
 static __inline__ void
-__SCNetworkReachabilityPerformInline(SCNetworkReachabilityRef target, Boolean needResolve)
+__SCNetworkReachabilityPerformInlineNoLock(SCNetworkReachabilityRef target, Boolean needResolve)
 {
        dispatch_queue_t                queue;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       pthread_mutex_lock(&targetPrivate->lock);
+       MUTEX_LOCK(&targetPrivate->lock);
 
        if (needResolve) {
                // allow the DNS query to be [re-]started
@@ -1843,12 +2139,18 @@ __SCNetworkReachabilityPerformInline(SCNetworkReachabilityRef target, Boolean ne
 
        queue = targetPrivate->dispatchQueue;
        if (queue != NULL) {
+               dispatch_group_t        group;
+
                dispatch_retain(queue);
 
-               pthread_mutex_unlock(&targetPrivate->lock);
+               group = targetPrivate->dispatchGroup;
+               dispatch_group_enter(group);
+
+               MUTEX_UNLOCK(&targetPrivate->lock);
 
                dispatch_sync(queue, ^{
-                       rlsPerform((void *)target);
+                       reachPerform((void *)target);
+                       dispatch_group_leave(group);
                        dispatch_release(queue);
                });
        } else {
@@ -1857,25 +2159,97 @@ __SCNetworkReachabilityPerformInline(SCNetworkReachabilityRef target, Boolean ne
                        _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
                }
 
-               pthread_mutex_unlock(&targetPrivate->lock);
+               MUTEX_UNLOCK(&targetPrivate->lock);
+       }
+
+       return;
+}
+
+
+#ifdef HAVE_REACHABILITY_SERVER
+/*
+ * __SCNetworkReachabilityPerformNoLock
+ *
+ * Calls reachPerform()
+ * - caller must *not* be holding the target lock
+ * - caller must *not* running on the __SCNetworkReachability_concurrent_queue()
+ */
+__private_extern__
+void
+__SCNetworkReachabilityPerformNoLock(SCNetworkReachabilityRef target)
+{
+       CFRetain(target);
+       dispatch_async(__SCNetworkReachability_concurrent_queue(), ^{
+               __SCNetworkReachabilityPerformInlineNoLock(target, FALSE);
+               CFRelease(target);
+       });
+
+       return;
+}
+#endif // HAVE_REACHABILITY_SERVER
+
+
+/*
+ * __SCNetworkReachabilityPerformConcurrent
+ *
+ * Calls reachPerform()
+ * - caller must be holding the target lock
+ * - caller running on the __SCNetworkReachability_concurrent_queue()
+ */
+static __inline__ void
+__SCNetworkReachabilityPerformConcurrent(SCNetworkReachabilityRef target)
+{
+       dispatch_queue_t                queue;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       queue = targetPrivate->dispatchQueue;
+       if (queue != NULL) {
+               dispatch_retain(queue);
+               CFRetain(target);
+               dispatch_group_async(targetPrivate->dispatchGroup, queue, ^{
+                       reachPerform((void *)target);
+                       CFRelease(target);
+                       dispatch_release(queue);
+               });
+       } else {
+               if (targetPrivate->rls != NULL) {
+                       CFRunLoopSourceSignal(targetPrivate->rls);
+                       _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
+               }
        }
 
        return;
 }
 
 
+/*
+ * __SCNetworkReachabilityPerform
+ *
+ * Calls reachPerform()
+ * - caller must be holding the target lock
+ * - caller not running on the __SCNetworkReachability_concurrent_queue()
+ */
 static void
 __SCNetworkReachabilityPerform(SCNetworkReachabilityRef target)
 {
+       dispatch_queue_t                queue;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       if (targetPrivate->dispatchQueue != NULL) {
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       queue = targetPrivate->dispatchQueue;
+       if (queue != NULL) {
+               dispatch_retain(queue);
                CFRetain(target);
-               dispatch_async(targetPrivate->dispatchQueue,
-                              ^{
-                                      rlsPerform((void *)target);
-                                      CFRelease(target);
-                              });
+               dispatch_group_async(targetPrivate->dispatchGroup, __SCNetworkReachability_concurrent_queue(), ^{
+                       dispatch_sync(queue, ^{
+                               reachPerform((void *)target);
+                               CFRelease(target);
+                               dispatch_release(queue);
+                       });
+               });
        } else if (targetPrivate->rls != NULL) {
                CFRunLoopSourceSignal(targetPrivate->rls);
                _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList);
@@ -1884,6 +2258,7 @@ __SCNetworkReachabilityPerform(SCNetworkReachabilityRef target)
        return;
 }
 
+
 static SCNetworkReachabilityPrivateRef
 __SCNetworkReachabilityCreatePrivate(CFAllocatorRef    allocator)
 {
@@ -1903,16 +2278,11 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef     allocator)
                return NULL;
        }
 
-       pthread_mutex_init(&targetPrivate->lock, NULL);
+       MUTEX_INIT(&targetPrivate->lock);
 
        targetPrivate->name                             = NULL;
        targetPrivate->serv                             = NULL;
-       bzero(&targetPrivate->hints, sizeof(targetPrivate->hints));
-       targetPrivate->hints.ai_flags = AI_ADDRCONFIG;
-#ifdef AI_PARALLEL
-       targetPrivate->hints.ai_flags |= AI_PARALLEL;
-#endif /* AI_PARALLEL */
-
+       targetPrivate->hints                            = HINTS_DEFAULT;
        targetPrivate->needResolve                      = FALSE;
        targetPrivate->resolvedAddress                  = NULL;
        targetPrivate->resolvedAddressError             = NETDB_SUCCESS;
@@ -1922,6 +2292,7 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef       allocator)
        targetPrivate->localAddress                     = NULL;
        targetPrivate->remoteAddress                    = NULL;
 
+       targetPrivate->cycle                            = 1;
        targetPrivate->info                             = NOT_REACHABLE;
        targetPrivate->last_notify                      = NOT_REPORTED;
 
@@ -1938,12 +2309,18 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef     allocator)
        targetPrivate->dnsMP                            = MACH_PORT_NULL;
        targetPrivate->dnsPort                          = NULL;
        targetPrivate->dnsRLS                           = NULL;
+       targetPrivate->dnsSource                        = NULL;
        targetPrivate->dnsQueryStart                    = TIME_ZERO;
        targetPrivate->dnsQueryEnd                      = TIME_ZERO;
        targetPrivate->dnsRetry                         = NULL;
        targetPrivate->dnsRetryCount                    = 0;
 
        targetPrivate->last_dns                         = TIME_ZERO;
+       targetPrivate->last_network                     = TIME_ZERO;
+#if    !TARGET_OS_IPHONE
+       targetPrivate->last_power                       = TIME_ZERO;
+#endif // !TARGET_OS_IPHONE
+       targetPrivate->last_push                        = TIME_ZERO;
 
        targetPrivate->onDemandBypass                   = FALSE;
        targetPrivate->onDemandName                     = NULL;
@@ -1952,6 +2329,26 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef      allocator)
        targetPrivate->onDemandServiceID                = NULL;
 
 
+       targetPrivate->llqActive                        = FALSE;
+       targetPrivate->llqBypass                        = D_llqBypass;
+       targetPrivate->llqTarget                        = NULL;
+       targetPrivate->llqTimer                         = NULL;
+
+#ifdef HAVE_REACHABILITY_SERVER
+       targetPrivate->serverActive                     = FALSE;
+       targetPrivate->serverBypass                     = D_serverBypass;
+       targetPrivate->serverScheduled                  = FALSE;
+       targetPrivate->serverInfo                       = NOT_REACHABLE;
+
+       targetPrivate->serverDigest                     = NULL;
+       targetPrivate->serverGroup                      = NULL;
+       targetPrivate->serverInfoValid                  = FALSE;
+       targetPrivate->serverQueryActive                = 0;
+       targetPrivate->serverQueue                      = NULL;
+       targetPrivate->serverReferences                 = 0;
+       targetPrivate->serverWatchers                   = NULL;
+#endif // HAVE_REACHABILITY_SERVER
+
        targetPrivate->log_prefix[0] = '\0';
        if (_sc_log > 0) {
                snprintf(targetPrivate->log_prefix,
@@ -2034,8 +2431,9 @@ SCNetworkReachabilityCreateWithAddress(CFAllocatorRef             allocator,
        targetPrivate->remoteAddress = CFAllocatorAllocate(NULL, address->sa_len, 0);
        bcopy(address, targetPrivate->remoteAddress, address->sa_len);
 
-       SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%screate w/address %@"),
+       SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%s%s %@"),
              targetPrivate->log_prefix,
+             DEBUG_REACHABILITY_TYPE_ADDRESS,
              targetPrivate);
 
        return (SCNetworkReachabilityRef)targetPrivate;
@@ -2087,8 +2485,9 @@ SCNetworkReachabilityCreateWithAddressPair(CFAllocatorRef         allocator,
                bcopy(remoteAddress, targetPrivate->remoteAddress, remoteAddress->sa_len);
        }
 
-       SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%screate w/address pair %@"),
+       SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%s%s %@"),
              targetPrivate->log_prefix,
+             DEBUG_REACHABILITY_TYPE_ADDRESSPAIR,
              targetPrivate);
 
        return (SCNetworkReachabilityRef)targetPrivate;
@@ -2099,9 +2498,12 @@ SCNetworkReachabilityRef
 SCNetworkReachabilityCreateWithName(CFAllocatorRef     allocator,
                                    const char          *nodename)
 {
+       union {
+               struct sockaddr         sa;
+               struct sockaddr_in      sin;
+               struct sockaddr_in6     sin6;
+       } addr;
        int                             nodenameLen;
-       struct sockaddr_in              sin;
-       struct sockaddr_in6             sin6;
        SCNetworkReachabilityPrivateRef targetPrivate;
 
        if (nodename == NULL) {
@@ -2115,29 +2517,9 @@ SCNetworkReachabilityCreateWithName(CFAllocatorRef       allocator,
                return NULL;
        }
 
-       /* check if this "nodename" is really an IP[v6] address in disguise */
-
-       bzero(&sin, sizeof(sin));
-       sin.sin_len    = sizeof(sin);
-       sin.sin_family = AF_INET;
-       if (inet_aton(nodename, &sin.sin_addr) == 1) {
-               /* if IPv4 address */
-               return SCNetworkReachabilityCreateWithAddress(allocator, (struct sockaddr *)&sin);
-       }
-
-       bzero(&sin6, sizeof(sin6));
-       sin6.sin6_len    = sizeof(sin6);
-       sin6.sin6_family = AF_INET6;
-       if (inet_pton(AF_INET6, nodename, &sin6.sin6_addr) == 1) {
-               /* if IPv6 address */
-               char    *p;
-
-               p = strchr(nodename, '%');
-               if (p != NULL) {
-                       sin6.sin6_scope_id = if_nametoindex(p + 1);
-               }
-
-               return SCNetworkReachabilityCreateWithAddress(allocator, (struct sockaddr *)&sin6);
+       if (_SC_string_to_sockaddr(nodename, AF_UNSPEC, (void *)&addr, sizeof(addr)) != NULL) {
+               /* if this "nodename" is really an IP[v6] address in disguise */
+               return SCNetworkReachabilityCreateWithAddress(allocator, &addr.sa);
        }
 
        targetPrivate = __SCNetworkReachabilityCreatePrivate(allocator);
@@ -2152,9 +2534,13 @@ SCNetworkReachabilityCreateWithName(CFAllocatorRef       allocator,
 
        targetPrivate->needResolve = TRUE;
        targetPrivate->info.flags |= kSCNetworkReachabilityFlagsFirstResolvePending;
+#ifdef HAVE_REACHABILITY_SERVER
+       targetPrivate->serverInfo.flags |= kSCNetworkReachabilityFlagsFirstResolvePending;
+#endif // HAVE_REACHABILITY_SERVER
 
-       SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%screate w/name %@"),
+       SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%s%s %@"),
              targetPrivate->log_prefix,
+             DEBUG_REACHABILITY_TYPE_NAME,
              targetPrivate);
 
        return (SCNetworkReachabilityRef)targetPrivate;
@@ -2169,11 +2555,16 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef   allocator,
 {
        const struct sockaddr           *addr_l         = NULL;
        const struct sockaddr           *addr_r         = NULL;
-       CFBooleanRef                    bypass;
        CFDataRef                       data;
        struct addrinfo                 *hints          = NULL;
        CFStringRef                     interface       = NULL;
+       CFBooleanRef                    llqBypass;
        CFStringRef                     nodename;
+       CFBooleanRef                    onDemandBypass;
+       CFBooleanRef                    resolverBypass;
+#ifdef HAVE_REACHABILITY_SERVER
+       CFBooleanRef                    serverBypass;
+#endif // HAVE_REACHABILITY_SERVER
        CFStringRef                     servname;
        SCNetworkReachabilityRef        target;
        SCNetworkReachabilityPrivateRef targetPrivate;
@@ -2218,7 +2609,8 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef     allocator,
                        return NULL;
                }
 
-               hints = (struct addrinfo *)CFDataGetBytePtr(data);
+               /* ALIGN: CF aligns to >8 byte boundries */
+               hints = (struct addrinfo *)(void *)CFDataGetBytePtr(data);
                if ((hints->ai_addrlen   != 0)    ||
                    (hints->ai_addr      != NULL) ||
                    (hints->ai_canonname != NULL) ||
@@ -2233,13 +2625,32 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef   allocator,
                _SCErrorSet(kSCStatusInvalidArgument);
                return NULL;
        }
-       bypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionConnectionOnDemandByPass);
-       if ((bypass != NULL) && !isA_CFBoolean(bypass)) {
+       onDemandBypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionConnectionOnDemandBypass);
+       if ((onDemandBypass != NULL) && !isA_CFBoolean(onDemandBypass)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+       resolverBypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionResolverBypass);
+       if ((resolverBypass != NULL) && !isA_CFBoolean(resolverBypass)) {
                _SCErrorSet(kSCStatusInvalidArgument);
                return NULL;
        }
 
 
+       llqBypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionLongLivedQueryBypass);
+       if ((llqBypass != NULL) && !isA_CFBoolean(llqBypass)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
+#ifdef HAVE_REACHABILITY_SERVER
+       serverBypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionServerBypass);
+       if ((serverBypass != NULL) && !isA_CFBoolean(serverBypass)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+#endif // HAVE_REACHABILITY_SERVER
+
        if ((nodename != NULL) || (servname != NULL)) {
                const char      *name;
 
@@ -2291,13 +2702,47 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef   allocator,
        }
 
 
-       if (bypass != NULL) {
-               targetPrivate->onDemandBypass = CFBooleanGetValue(bypass);
+       if (llqBypass != NULL) {
+               targetPrivate->llqBypass = CFBooleanGetValue(llqBypass);
        }
 
-       SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%s    + options %@"),
-             targetPrivate->log_prefix,
-             targetPrivate);
+       if (onDemandBypass != NULL) {
+               targetPrivate->onDemandBypass = CFBooleanGetValue(onDemandBypass);
+       }
+
+       if (resolverBypass != NULL) {
+               targetPrivate->resolverBypass = CFBooleanGetValue(resolverBypass);
+       }
+
+#ifdef HAVE_REACHABILITY_SERVER
+       if (serverBypass != NULL) {
+               targetPrivate->serverBypass = CFBooleanGetValue(serverBypass);
+       }
+#endif // HAVE_REACHABILITY_SERVER
+
+       if (_sc_debug && (_sc_log > 0)) {
+               const char      *opt;
+
+               switch (targetPrivate->type) {
+                       case reachabilityTypeName :
+                               opt = DEBUG_REACHABILITY_TYPE_NAME_OPTIONS;
+                               break;
+                       case reachabilityTypeAddress :
+                               opt = DEBUG_REACHABILITY_TYPE_ADDRESS_OPTIONS;
+                               break;
+                       case reachabilityTypeAddressPair :
+                               opt = DEBUG_REACHABILITY_TYPE_ADDRESSPAIR_OPTIONS;
+                               break;
+                       default :
+                               opt = "???";
+                               break;
+               }
+
+               SCLog(TRUE, LOG_INFO, CFSTR("%s%s %@"),
+                     targetPrivate->log_prefix,
+                     opt,
+                     targetPrivate);
+       }
 
        return (SCNetworkReachabilityRef)targetPrivate;
 }
@@ -2354,6 +2799,8 @@ __SCNetworkReachabilitySetResolvedAddress(int32_t                 status,
        struct addrinfo                         *resP;
        SCNetworkReachabilityPrivateRef         targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
        if (targetPrivate->resolvedAddress != NULL) {
                CFRelease(targetPrivate->resolvedAddress);
                targetPrivate->resolvedAddress = NULL;
@@ -2409,7 +2856,7 @@ __SCNetworkReachabilityCallbackSetResolvedAddress(int32_t status, struct addrinf
 
        __dns_query_end(target,
                        ((status == 0) && (res != NULL)),       // if successful query
-                       TRUE,                                   // async
+                       dns_query_async,                        // async
                        &targetPrivate->dnsQueryStart,          // start time
                        &targetPrivate->dnsQueryEnd);           // end time
 
@@ -2458,132 +2905,219 @@ replyMPCopyDescription(const void *info)
 
 
 static void
-processAsyncDNSReply(mach_port_t mp, void *msg, SCNetworkReachabilityRef target);
+getaddrinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info);
 
 
-static void
-getaddrinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
+static Boolean
+enqueueAsyncDNSQuery_dispatch(SCNetworkReachabilityRef target)
 {
-       mach_port_t                     mp      = CFMachPortGetPort(port);
-       SCNetworkReachabilityRef        target  = (SCNetworkReachabilityRef)info;
+       mach_port_t                     mp;
+       dispatch_source_t               source;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       processAsyncDNSReply(mp, msg, target);
-       return;
-}
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
 
+       mp = targetPrivate->dnsMP;
 
-static boolean_t
-SCNetworkReachabilityNotifyMIGCallback(mach_msg_header_t *message, mach_msg_header_t *reply)
-{
-       mach_port_t                     mp      = message->msgh_local_port;
-       SCNetworkReachabilityRef        target  = dispatch_get_context(dispatch_get_current_queue());
+       // mach_port context <-- NULL (no msg received)
+       mach_port_set_context(mach_task_self(), mp, (mach_vm_address_t)(uintptr_t)NULL);
 
-       processAsyncDNSReply(mp, message, target);
-       reply->msgh_remote_port = MACH_PORT_NULL;
-       return false;
+       // create dispatch source to handle DNS reply
+       source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
+                                       mp,
+                                       0,
+                                       __SCNetworkReachability_concurrent_queue());
+       if (source == NULL) {
+               SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability dispatch_source_create() failed"));
+               return FALSE;
+       }
+
+       //
+       // We created the dispatch_source to listen for (and process) the mach IPC
+       // reply to our async DNS query.  Because the source handler runs asychronously
+       // we need to ensure that we're holding a reference to the target. Here, we take
+       // a reference and setup the dispatch_source finalizer to drop it.
+       //
+       CFRetain(target);
+       dispatch_set_context(source, (void *)target);
+       dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease);
+
+       dispatch_source_set_event_handler(source, ^{
+               mach_msg_size_t                 msg_size        = 8192;
+               const mach_msg_options_t        options         = MACH_RCV_MSG
+                                                               | MACH_RCV_LARGE
+                                                               | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX)
+                                                               | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
+
+               while (TRUE) {
+                       kern_return_t           kr;
+                       mach_msg_header_t       *msg    = (mach_msg_header_t *)malloc(msg_size);
+
+                       kr = mach_msg(msg,                      /* msg */
+                                     options,                  /* options */
+                                     0,                        /* send_size */
+                                     msg_size,                 /* rcv_size */
+                                     mp,                       /* rcv_name */
+                                     MACH_MSG_TIMEOUT_NONE,    /* timeout */
+                                     MACH_PORT_NULL);          /* notify */
+                       if (kr == KERN_SUCCESS) {
+                               // mach_port context <-- msg
+                               mach_port_set_context(mach_task_self(),
+                                                     mp,
+                                                     (mach_vm_address_t)(uintptr_t)msg);
+                       } else if (kr == MACH_RCV_TOO_LARGE) {
+                               msg_size *= 2;
+                               free(msg);
+                               continue;
+                       } else {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("SCNetworkReachability async DNS handler, kr=0x%x"),
+                                     kr);
+                               free(msg);
+                       }
+                       break;
+               }
+
+               dispatch_source_cancel(source);
+       });
+
+       dispatch_source_set_cancel_handler(source, ^{
+#if    !TARGET_OS_EMBEDDED
+               mach_vm_address_t       context;
+#else  // !TARGET_OS_EMBEDDED
+               mach_port_context_t     context;
+#endif // !TARGET_OS_EMBEDDED
+               kern_return_t           kr;
+               mach_port_t             mp;
+
+               // get the [async DNS query] mach port
+               mp = (mach_port_t)dispatch_source_get_handle(source);
+
+               // check if we have a received message
+               kr = mach_port_get_context(mach_task_self(), mp, &context);
+               if (kr == KERN_SUCCESS) {
+                       void    *msg;
+
+                       msg = (void *)(uintptr_t)context;
+                       if (msg != NULL) {
+                               MUTEX_LOCK(&targetPrivate->lock);
+                               getaddrinfo_async_handle_reply(msg);
+                               targetPrivate->dnsSource = NULL;
+                               targetPrivate->dnsMP = MACH_PORT_NULL;
+                               MUTEX_UNLOCK(&targetPrivate->lock);
+                               free(msg);
+                       } else {
+                               getaddrinfo_async_cancel(mp);
+                       }
+               }
+
+               dispatch_release(source);
+       });
+
+       targetPrivate->dnsSource = source;
+       dispatch_resume(source);
+
+       return TRUE;
 }
 
 
 static Boolean
-enqueueAsyncDNSQuery(SCNetworkReachabilityRef target, mach_port_t mp)
+enqueueAsyncDNSQuery_CF(SCNetworkReachabilityRef target)
 {
-       CFMachPortContext               context         = { 0
-                                                         , (void *)target
-                                                         , CFRetain
-                                                         , CFRelease
-                                                         , replyMPCopyDescription
-                                                         };
+       CFMachPortContext               context = { 0
+                                                 , (void *)target
+                                                 , CFRetain
+                                                 , CFRelease
+                                                 , replyMPCopyDescription
+                                                 };
+       CFIndex                         i;
+       mach_port_t                     mp;
+       CFIndex                         n;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       targetPrivate->dnsMP   = mp;
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       mp = targetPrivate->dnsMP;
+
        targetPrivate->dnsPort = _SC_CFMachPortCreateWithPort("SCNetworkReachability",
                                                              mp,
                                                              getaddrinfo_async_handleCFReply,
                                                              &context);
-       if (targetPrivate->dispatchQueue != NULL) {
-               targetPrivate->asyncDNSQueue = dispatch_queue_create("com.apple.SCNetworkReachabilty.async_DNS_query", NULL);
-               if (targetPrivate->asyncDNSQueue == NULL) {
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability dispatch_queue_create() failed"));
-                       goto fail;
-               }
-               CFRetain(target);       // Note: will be released when the dispatch queue is released
-               dispatch_set_context(targetPrivate->asyncDNSQueue, (void *)target);
-               dispatch_set_finalizer_f(targetPrivate->asyncDNSQueue, (dispatch_function_t)CFRelease);
-
-               targetPrivate->asyncDNSSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
-                                                                      mp,
-                                                                      0,
-                                                                      targetPrivate->asyncDNSQueue);
-               if (targetPrivate->asyncDNSSource == NULL) {
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability dispatch_source_create() failed"));
-                       goto fail;
-               }
-               dispatch_source_set_event_handler(targetPrivate->asyncDNSSource, ^{
-                       dispatch_mig_server(targetPrivate->asyncDNSSource,
-                                           sizeof(mach_msg_header_t),
-                                           SCNetworkReachabilityNotifyMIGCallback);
-               });
-               dispatch_resume(targetPrivate->asyncDNSSource);
-       } else if (targetPrivate->rls != NULL) {
-               CFIndex i;
-               CFIndex n;
+       if (targetPrivate->dnsPort == NULL) {
+               SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability CFMachPortCreateWithPort() failed"));
+               goto fail;
+       }
 
-               targetPrivate->dnsRLS = CFMachPortCreateRunLoopSource(NULL, targetPrivate->dnsPort, 0);
+       targetPrivate->dnsRLS = CFMachPortCreateRunLoopSource(NULL, targetPrivate->dnsPort, 0);
+       if (targetPrivate->dnsRLS == NULL) {
+               SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability CFMachPortCreateRunLoopSource() failed"));
+               goto fail;
+       }
 
-               n = CFArrayGetCount(targetPrivate->rlList);
-               for (i = 0; i < n; i += 3) {
-                       CFRunLoopRef    rl      = (CFRunLoopRef)CFArrayGetValueAtIndex(targetPrivate->rlList, i+1);
-                       CFStringRef     rlMode  = (CFStringRef) CFArrayGetValueAtIndex(targetPrivate->rlList, i+2);
+       n = CFArrayGetCount(targetPrivate->rlList);
+       for (i = 0; i < n; i += 3) {
+               CFRunLoopRef    rl      = (CFRunLoopRef)CFArrayGetValueAtIndex(targetPrivate->rlList, i+1);
+               CFStringRef     rlMode  = (CFStringRef) CFArrayGetValueAtIndex(targetPrivate->rlList, i+2);
 
-                       CFRunLoopAddSource(rl, targetPrivate->dnsRLS, rlMode);
-               }
+               CFRunLoopAddSource(rl, targetPrivate->dnsRLS, rlMode);
        }
 
        return TRUE;
 
     fail :
 
-       if (targetPrivate->asyncDNSSource != NULL) {
-               dispatch_source_cancel(targetPrivate->asyncDNSSource);
-               dispatch_release(targetPrivate->asyncDNSSource);
-               targetPrivate->asyncDNSSource = NULL;
+       if (targetPrivate->dnsRLS != NULL) {
+               CFRunLoopSourceInvalidate(targetPrivate->dnsRLS);
+               CFRelease(targetPrivate->dnsRLS);
+               targetPrivate->dnsRLS = NULL;
        }
-       if (targetPrivate->asyncDNSQueue != NULL) {
-               dispatch_release(targetPrivate->asyncDNSQueue);
-               targetPrivate->asyncDNSQueue = NULL;
+       if (targetPrivate->dnsPort != NULL) {
+               CFMachPortInvalidate(targetPrivate->dnsPort);
+               CFRelease(targetPrivate->dnsPort);
+               targetPrivate->dnsPort = NULL;
        }
 
-       CFMachPortInvalidate(targetPrivate->dnsPort);
-       CFRelease(targetPrivate->dnsPort);
-       targetPrivate->dnsPort = NULL;
-       targetPrivate->dnsMP = MACH_PORT_NULL;
-
-       _SCErrorSet(kSCStatusFailed);
        return FALSE;
 }
 
 
-static void
-dequeueAsyncDNSQuery(SCNetworkReachabilityRef target)
+static Boolean
+enqueueAsyncDNSQuery(SCNetworkReachabilityRef target, mach_port_t mp)
 {
+       Boolean                         ok              = FALSE;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       if (targetPrivate->asyncDNSSource != NULL) {
-               dispatch_source_cancel(targetPrivate->asyncDNSSource);
-               if (targetPrivate->asyncDNSQueue != dispatch_get_current_queue()) {
-                       // ensure the cancellation has completed
-                       pthread_mutex_unlock(&targetPrivate->lock);
-                       dispatch_sync(targetPrivate->asyncDNSQueue, ^{});
-                       pthread_mutex_lock(&targetPrivate->lock);
-               }
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       targetPrivate->dnsMP = mp;
+
+       if (targetPrivate->dispatchQueue != NULL) {
+               ok = enqueueAsyncDNSQuery_dispatch(target);
+       } else if (targetPrivate->rls != NULL) {
+               ok = enqueueAsyncDNSQuery_CF(target);
        }
-       if (targetPrivate->asyncDNSSource != NULL) {
-               dispatch_release(targetPrivate->asyncDNSSource);
-               targetPrivate->asyncDNSSource = NULL;
+
+       if (!ok) {
+               targetPrivate->dnsMP = MACH_PORT_NULL;
+               _SCErrorSet(kSCStatusFailed);
+               return FALSE;
        }
-       if (targetPrivate->asyncDNSQueue != NULL) {
-               dispatch_release(targetPrivate->asyncDNSQueue);
-               targetPrivate->asyncDNSQueue = NULL;
+
+       return TRUE;
+}
+
+
+static void
+dequeueAsyncDNSQuery(SCNetworkReachabilityRef target, Boolean cancel)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       if (targetPrivate->dnsPort != NULL) {
+               CFMachPortInvalidate(targetPrivate->dnsPort);
+               CFRelease(targetPrivate->dnsPort);
+               targetPrivate->dnsPort = NULL;
        }
 
        if (targetPrivate->dnsRLS != NULL) {
@@ -2591,10 +3125,16 @@ dequeueAsyncDNSQuery(SCNetworkReachabilityRef target)
                targetPrivate->dnsRLS = NULL;
        }
 
-       if (targetPrivate->dnsPort != NULL) {
-               CFMachPortInvalidate(targetPrivate->dnsPort);
-               CFRelease(targetPrivate->dnsPort);
-               targetPrivate->dnsPort = NULL;
+       if (targetPrivate->dnsSource != NULL) {
+               dispatch_source_cancel(targetPrivate->dnsSource);
+               targetPrivate->dnsSource = NULL;
+               cancel = FALSE;         // the cancellation handler does the work
+       }
+
+       if (targetPrivate->dnsMP != MACH_PORT_NULL) {
+               if (cancel) {
+                       getaddrinfo_async_cancel(targetPrivate->dnsMP);
+               }
                targetPrivate->dnsMP = MACH_PORT_NULL;
        }
 
@@ -2603,23 +3143,25 @@ dequeueAsyncDNSQuery(SCNetworkReachabilityRef target)
 
 
 static void
-processAsyncDNSReply(mach_port_t mp, void *msg, SCNetworkReachabilityRef target)
+getaddrinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
 {
+       mach_port_t                     mp              = CFMachPortGetPort(port);
        int32_t                         status;
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)info;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       pthread_mutex_lock(&targetPrivate->lock);
+       MUTEX_LOCK(&targetPrivate->lock);
 
        if (mp != targetPrivate->dnsMP) {
                // we've received a callback on the async DNS port but since the
                // associated CFMachPort doesn't match than the request must have
                // already been cancelled.
                SCLog(TRUE, LOG_ERR, CFSTR("processAsyncDNSReply(): mp != targetPrivate->dnsMP"));
-               pthread_mutex_unlock(&targetPrivate->lock);
+               MUTEX_UNLOCK(&targetPrivate->lock);
                return;
        }
 
-       dequeueAsyncDNSQuery(target);
+       dequeueAsyncDNSQuery(target, FALSE);
        status = getaddrinfo_async_handle_reply(msg);
        if ((status == 0) &&
            (targetPrivate->resolvedAddress == NULL) && (targetPrivate->resolvedAddressError == NETDB_SUCCESS)) {
@@ -2632,7 +3174,7 @@ processAsyncDNSReply(mach_port_t mp, void *msg, SCNetworkReachabilityRef target)
                }
        }
 
-       pthread_mutex_unlock(&targetPrivate->lock);
+       MUTEX_UNLOCK(&targetPrivate->lock);
 
        return;
 }
@@ -2643,43 +3185,50 @@ check_resolver_reachability(ReachabilityStoreInfoRef    store_info,
                            dns_resolver_t              *resolver,
                            SCNetworkReachabilityFlags  *flags,
                            Boolean                     *haveDNS,
+                           uint32_t                    *resolver_if_index,
                            const char                  *log_prefix)
 {
-       int             i;
        Boolean         ok      = TRUE;
 
-       *flags   = kSCNetworkReachabilityFlagsReachable;
-       *haveDNS = FALSE;
+       if (resolver_if_index) *resolver_if_index = 0;
 
-       for (i = 0; i < resolver->n_nameserver; i++) {
-               struct sockaddr         *address        = resolver->nameserver[i];
-               ReachabilityInfo        ns_info;
+       if (resolver->n_nameserver > 0) {
+#if    !TARGET_IPHONE_SIMULATOR
+               *flags   = (SCNetworkReachabilityFlags)resolver->reach_flags;
+               if (resolver_if_index != NULL) {
+                       *resolver_if_index = resolver->if_index;
+               }
+#else  // !TARGET_IPHONE_SIMULATOR
+               int     i;
 
-               *haveDNS = TRUE;
+               *flags = kSCNetworkReachabilityFlagsReachable;
 
-               if (address->sa_family != AF_INET) {
-                       /*
-                        * we need to skip non-IPv4 DNS server
-                        * addresses (at least until [3510431] has
-                        * been resolved).
-                        */
-                       continue;
-               }
+               for (i = 0; i < resolver->n_nameserver; i++) {
+                       struct sockaddr         *address        = resolver->nameserver[i];
+                       ReachabilityInfo        ns_info;
 
-               ok = checkAddress(store_info, address, resolver->if_index, &ns_info, log_prefix);
-               if (!ok) {
-                       /* not today */
-                       goto done;
-               }
+                       ok = checkAddress(store_info, address, resolver->if_index, &ns_info, log_prefix);
+                       if (!ok) {
+                               /* not today */
+                               break;
+                       }
 
-               if (rankReachability(ns_info.flags) < rankReachability(*flags)) {
-                       /* return the worst case result */
-                       *flags = ns_info.flags;
+                       if ((i == 0) ||
+                           (rankReachability(ns_info.flags) < rankReachability(*flags))) {
+                               /* return the worst case result */
+                               *flags = ns_info.flags;
+                               if (resolver_if_index != NULL) {
+                                       *resolver_if_index = ns_info.if_index;
+                               }
+                       }
                }
+#endif // !TARGET_IPHONE_SIMULATOR
+               *haveDNS = TRUE;
+       } else {
+               *flags   = kSCNetworkReachabilityFlagsReachable;
+               *haveDNS = FALSE;
        }
 
-    done :
-
        return ok;
 }
 
@@ -2691,6 +3240,8 @@ check_matching_resolvers(ReachabilityStoreInfoRef store_info,
                         unsigned int                   if_index,
                         SCNetworkReachabilityFlags     *flags,
                         Boolean                        *haveDNS,
+                        uint32_t                       *resolver_if_index,
+                        int                            *dns_config_index,
                         const char                     *log_prefix)
 {
        int             i;
@@ -2707,6 +3258,11 @@ check_matching_resolvers(ReachabilityStoreInfoRef        store_info,
                resolvers   = dns_config->scoped_resolver;
        }
 
+       /* In case we couldn't find a match, setting an index of -1
+          and resolver_if_index 0 */
+       if (dns_config_index != NULL) *dns_config_index = -1;
+       if (resolver_if_index != NULL) *resolver_if_index = 0;
+
        while (!matched && (name != NULL)) {
                int     len;
 
@@ -2733,11 +3289,13 @@ check_matching_resolvers(ReachabilityStoreInfoRef       store_info,
                                         * if name matches domain
                                         */
                                        matched = TRUE;
-                                       ok = check_resolver_reachability(store_info, resolver, flags, haveDNS, log_prefix);
+                                       ok = check_resolver_reachability(store_info, resolver, flags, haveDNS,
+                                                                        resolver_if_index, log_prefix);
                                        if (!ok) {
                                                /* not today */
                                                return FALSE;
                                        }
+                                       if (dns_config_index != NULL) *dns_config_index = i;
                                }
                        }
                }
@@ -2931,7 +3489,10 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef store_info,
                                const char                      *nodename,
                                const char                      *servname,
                                unsigned int                    if_index,
-                               const char                      *log_prefix)
+                               uint32_t                        *resolver_if_index,
+                               int                             *dns_config_index,
+                               const char                      *log_prefix
+                               )
 {
        dns_resolver_t          *default_resolver;
        dns_configuration_t     *dns;
@@ -2944,6 +3505,9 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef  store_info,
        Boolean                 ok                      = TRUE;
        Boolean                 useDefault              = FALSE;
 
+       if (resolver_if_index) *resolver_if_index = 0;
+       if (dns_config_index) *dns_config_index = -1;
+
        /*
         * We first assume that all of the configured DNS servers
         * are available.  Since we don't know which name server will
@@ -2977,8 +3541,6 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef  store_info,
                goto done;
        }
 
-       *flags = kSCNetworkReachabilityFlagsReachable;
-
        if (fqdn[len - 1] == '.') {
                isFQDN = TRUE;
 
@@ -2996,7 +3558,9 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef  store_info,
        /*
         * check if the provided name matches a supplemental domain
         */
-       found = check_matching_resolvers(store_info, dns->config, fqdn, if_index, flags, haveDNS, log_prefix);
+       found = check_matching_resolvers(store_info, dns->config, fqdn, if_index,
+                                        flags, haveDNS, resolver_if_index,
+                                        dns_config_index, log_prefix);
 
        if (!found && !isFQDN) {
                /*
@@ -3059,6 +3623,8 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef  store_info,
                                                                 if_index,
                                                                 flags,
                                                                 haveDNS,
+                                                                resolver_if_index,
+                                                                dns_config_index,
                                                                 log_prefix);
                                free(search_fqdn);
                        }
@@ -3101,6 +3667,8 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef  store_info,
                                                                 if_index,
                                                                 flags,
                                                                 haveDNS,
+                                                                resolver_if_index,
+                                                                dns_config_index,
                                                                 log_prefix);
                                free(search_fqdn);
 
@@ -3114,7 +3682,9 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef  store_info,
                /*
                 * check the reachability of the default resolver
                 */
-               ok = check_resolver_reachability(store_info, default_resolver, flags, haveDNS, log_prefix);
+               ok = check_resolver_reachability(store_info, default_resolver, flags, haveDNS,
+                                                resolver_if_index, log_prefix);
+               if (ok && dns_config_index != NULL) *dns_config_index = 0;
        }
 
        if (fqdn != nodename)   free(fqdn);
@@ -3139,20 +3709,47 @@ _SC_checkResolverReachability(SCDynamicStoreRef                 *storeP,
        Boolean                 ok;
        ReachabilityStoreInfo   store_info;
 
-       initReachabilityStoreInfo(&store_info);
-       ok = updateReachabilityStoreInfo(&store_info, storeP, AF_UNSPEC);
+       ReachabilityStoreInfo_init(&store_info);
+       ok = ReachabilityStoreInfo_update(&store_info, storeP, AF_UNSPEC);
        if (!ok) {
                goto done;
        }
 
-       ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, nodename, servname, 0, "");
+       ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, nodename,
+                                            servname, 0, NULL, NULL, "");
 
     done :
 
-       freeReachabilityStoreInfo(&store_info);
+       ReachabilityStoreInfo_free(&store_info);
        return ok;
 }
 
+Boolean
+__SC_checkResolverReachabilityInternal(SCDynamicStoreRef               *storeP,
+                                      SCNetworkReachabilityFlags       *flags,
+                                      Boolean                          *haveDNS,
+                                      const char                       *nodename,
+                                      const char                       *servname,
+                                      uint32_t                         *resolver_if_index,
+                                      int                              *dns_config_index)
+{
+       Boolean                 ok;
+       ReachabilityStoreInfo   store_info;
+
+       ReachabilityStoreInfo_init(&store_info);
+       ok = ReachabilityStoreInfo_update(&store_info, storeP, AF_UNSPEC);
+       if (!ok) {
+               goto done;
+       }
+
+       ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, nodename,
+                                            servname, 0, resolver_if_index, dns_config_index, "");
+
+    done :
+
+       ReachabilityStoreInfo_free(&store_info);
+       return ok;
+}
 
 /*
  * _SC_checkResolverReachabilityByAddress()
@@ -3171,8 +3768,8 @@ _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef          *storeP,
        char                    ptr_name[128];
        ReachabilityStoreInfo   store_info;
 
-       initReachabilityStoreInfo(&store_info);
-       ok = updateReachabilityStoreInfo(&store_info, storeP, AF_UNSPEC);
+       ReachabilityStoreInfo_init(&store_info);
+       ok = ReachabilityStoreInfo_update(&store_info, storeP, AF_UNSPEC);
        if (!ok) {
                goto done;
        }
@@ -3192,7 +3789,8 @@ _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef          *storeP,
                                in_addr_t       s_addr;
                                unsigned char   b[4];
                        } rev;
-                       struct sockaddr_in      *sin    = (struct sockaddr_in *)sa;
+                       /* ALIGN: assuming sa is aligned, then cast ok. */
+                       struct sockaddr_in      *sin    = (struct sockaddr_in *)(void *)sa;
 
                        /*
                         * build "PTR" query name
@@ -3210,7 +3808,8 @@ _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef          *storeP,
 
                case AF_INET6 : {
                        int                     s       = 0;
-                       struct sockaddr_in6     *sin6   = (struct sockaddr_in6 *)sa;
+                       /* ALIGN: assume sa is aligned, cast ok. */
+                       struct sockaddr_in6     *sin6   = (struct sockaddr_in6 *)(void *)sa;
                        int                     x       = sizeof(ptr_name);
                        int                     n;
 
@@ -3242,17 +3841,18 @@ _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef                *storeP,
                        goto done;
        }
 
-       ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, ptr_name, NULL, 0, "");
+       ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, ptr_name, NULL, 0, NULL, NULL, "");
 
     done :
 
-       freeReachabilityStoreInfo(&store_info);
+       ReachabilityStoreInfo_free(&store_info);
        return ok;
 }
 
 
 static Boolean
-startAsyncDNSQuery(SCNetworkReachabilityRef target) {
+startAsyncDNSQuery(SCNetworkReachabilityRef target)
+{
        int                             error   = 0;
        mach_port_t                     mp      = MACH_PORT_NULL;
        Boolean                         ok;
@@ -3293,57 +3893,419 @@ startAsyncDNSQuery(SCNetworkReachabilityRef target) {
 }
 
 
-#pragma mark -
+#pragma mark -
+
+
+static Boolean
+enqueueAsyncDNSRetry(SCNetworkReachabilityRef  target)
+{
+       int64_t                         delay;
+       dispatch_source_t               source;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
+                                       0,
+                                       0,
+                                       __SCNetworkReachability_concurrent_queue());
+       if (source == NULL) {
+               SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability retry dispatch_source_create() failed"));
+               return FALSE;
+       }
+
+       // retain the target ... and release it when the [timer] source is released
+       CFRetain(target);
+       dispatch_set_context(source, (void *)target);
+       dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease);
+
+       dispatch_source_set_event_handler(source, ^(void) {
+               __SCNetworkReachabilityPerformInlineNoLock(target, TRUE);
+       });
+
+       // start a one-shot timer
+       delay = targetPrivate->dnsRetryCount * EAI_NONAME_RETRY_DELAY_USEC * NSEC_PER_USEC;
+       dispatch_source_set_timer(source,
+                                 dispatch_time(DISPATCH_TIME_NOW, delay),      // start
+                                 0,                                            // interval
+                                 10 * NSEC_PER_MSEC);                          // leeway
+
+       targetPrivate->dnsRetry = source;
+       dispatch_resume(source);
+
+       return TRUE;
+}
+
+
+static void
+dequeueAsyncDNSRetry(SCNetworkReachabilityRef  target)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       if (targetPrivate->dnsRetry != NULL) {
+               dispatch_source_cancel(targetPrivate->dnsRetry);
+               dispatch_release(targetPrivate->dnsRetry);
+               targetPrivate->dnsRetry = NULL;
+       }
+
+       return;
+}
+
+
+#pragma mark -
+
+
+static dispatch_queue_t
+_llq_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create("SCNetworkReachabilty.longLivedQueries", NULL);
+       });
+
+       return q;
+}
+
+
+/*
+ * _llq_notify
+ *
+ * Called to push out a target's DNS changes
+ * - caller must be running on the _llq_queue()
+ */
+static void
+_llq_notify(const void *value, void *context)
+{
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)value;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       MUTEX_LOCK(&targetPrivate->lock);
+
+       __dns_query_end(target,
+                       (targetPrivate->resolvedAddressError == NETDB_SUCCESS), // if successful query
+                       dns_query_llq,                                          // long-lived-query
+                       &targetPrivate->dnsQueryStart,                          // start time
+                       &targetPrivate->dnsQueryEnd);                           // end time
+
+       if (targetPrivate->scheduled) {
+               __SCNetworkReachabilityPerform(target);
+       }
+
+       // last long-lived-query end time is new start time
+       targetPrivate->dnsQueryStart = targetPrivate->dnsQueryEnd;
+
+       MUTEX_UNLOCK(&targetPrivate->lock);
+       return;
+}
+
+
+/*
+ * _llq_callback
+ *
+ * Called to process mDNSResponder long-lived-query updates
+ * - caller must be running on the _llq_queue()
+ */
+static void
+_llq_callback(DNSServiceRef            sdRef,
+             DNSServiceFlags           flags,
+             uint32_t                  interfaceIndex,
+             DNSServiceErrorType       errorCode,
+             const char                *hostname,
+             const struct sockaddr     *address,
+             uint32_t                  ttl,
+             void                      *context)
+{
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)context;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       MUTEX_LOCK(&targetPrivate->lock);
+
+       if (targetPrivate->llqTimer != NULL) {
+               dispatch_source_cancel(targetPrivate->llqTimer);
+               dispatch_release(targetPrivate->llqTimer);
+               targetPrivate->llqTimer = NULL;
+       }
+
+       switch (errorCode) {
+               case kDNSServiceErr_NoError :
+                       if (address != NULL) {
+                               CFMutableArrayRef       addresses;
+                               CFDataRef               llqAddress;
+
+                               if (targetPrivate->resolvedAddress != NULL) {
+                                       if (isA_CFArray(targetPrivate->resolvedAddress)) {
+                                               addresses = CFArrayCreateMutableCopy(NULL, 0, targetPrivate->resolvedAddress);
+                                       } else {
+                                               addresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+                                       }
+
+                                       CFRelease(targetPrivate->resolvedAddress);
+                                       targetPrivate->resolvedAddress = NULL;
+                               } else {
+                                       addresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+                               }
+
+                               llqAddress = CFDataCreate(NULL, (void *)address, address->sa_len);
+                               if (flags & kDNSServiceFlagsAdd) {
+                                       // add address
+                                       CFArrayAppendValue(addresses, llqAddress);
+                               } else {
+                                       CFIndex i;
+
+                                       // remove address
+                                       i = CFArrayGetFirstIndexOfValue(addresses,
+                                                                       CFRangeMake(0, CFArrayGetCount(addresses)),
+                                                                       llqAddress);
+                                       if (i != kCFNotFound) {
+                                               CFArrayRemoveValueAtIndex(addresses, i);
+                                       }
+                               }
+                               CFRelease(llqAddress);
+
+                               if (CFArrayGetCount(addresses) > 0) {
+                                       targetPrivate->resolvedAddress      = addresses;
+                                       targetPrivate->resolvedAddressError = NETDB_SUCCESS;
+                               } else {
+                                       // if host not found
+                                       targetPrivate->resolvedAddress      = CFRetain(kCFNull);
+                                       targetPrivate->resolvedAddressError = EAI_NONAME;
+                                       CFRelease(addresses);
+                               }
+
+                               targetPrivate->needResolve = FALSE;
+                       }
+                       break;
+               case kDNSServiceErr_NoSuchRecord :
+                       if (address != NULL) {
+                               // no IPv4/IPv6 address for name (NXDOMAIN)
+                               if (targetPrivate->resolvedAddress == NULL) {
+                                       targetPrivate->resolvedAddress      = CFRetain(kCFNull);
+                                       targetPrivate->resolvedAddressError = EAI_NONAME;
+                               }
+                               targetPrivate->needResolve = FALSE;
+                       }
+                       break;
+               case kDNSServiceErr_Timeout :
+                       if (targetPrivate->resolvedAddress == NULL) {
+                               targetPrivate->resolvedAddress      = CFRetain(kCFNull);
+                               targetPrivate->resolvedAddressError = EAI_NONAME;
+                       }
+                       targetPrivate->needResolve = FALSE;
+                       break;
+               default :
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("%sSCNetworkReachability _llq_callback w/error=%d"),
+                             targetPrivate->log_prefix,
+                             errorCode);
+                       break;
+       }
+
+       MUTEX_UNLOCK(&targetPrivate->lock);
+
+       // the "more coming" flag applies to DNSService callouts for any/all
+       // hosts that are being watched so we need to keep track of the targets
+       // we have updated.  When we [finally] have the last callout then we
+       // push our notifications for all of the updated targets.
+
+       if (llqUpdated == NULL) {
+               llqUpdated = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+       }
+       CFSetAddValue(llqUpdated, target);
+
+       if (!(flags & kDNSServiceFlagsMoreComing)) {
+               CFSetApplyFunction(llqUpdated, _llq_notify, NULL);
+               CFRelease(llqUpdated);
+               llqUpdated = NULL;
+       }
+
+       return;
+}
+
+
+static Boolean
+enqueueLongLivedQuery(SCNetworkReachabilityRef target)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       if (targetPrivate->serv != NULL) {
+               // if "serv" provided, can't use DNSServiceGetAddrInfo
+               return FALSE;
+       }
+
+       if (memcmp(&targetPrivate->hints, &HINTS_DEFAULT, sizeof(targetPrivate->hints)) != 0) {
+               // non-default "hints" provided, can't use DNSServiceGetAddrInfo
+               return FALSE;
+       }
+
+       // mark the long lived query active
+       targetPrivate->llqActive = TRUE;
+
+       // track the DNS resolution time
+       __dns_query_start(&targetPrivate->dnsQueryStart, &targetPrivate->dnsQueryEnd);
+
+       CFRetain(target);
+       dispatch_async(_llq_queue(), ^{
+               DNSServiceErrorType     err;
+               dispatch_source_t       source;
+
+               MUTEX_LOCK(&targetPrivate->lock);
+
+               if (targetPrivate->llqTarget != NULL) {
+                       // if already running
+                       MUTEX_UNLOCK(&targetPrivate->lock);
+                       CFRelease(target);
+                       return;
+               }
+
+               // if needed, start interacting with mDNSResponder
+
+               if (llqMain == NULL) {
+                       err = DNSServiceCreateConnection(&llqMain);
+                       if (err != kDNSServiceErr_NoError) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("DNSServiceCreateConnection(&llqMain) failed, error = %d"),
+                                     err);
+
+                               targetPrivate->llqActive = FALSE;
+
+                               MUTEX_UNLOCK(&targetPrivate->lock);
+                               CFRelease(target);
+                               return;
+                       }
 
+                       err = DNSServiceSetDispatchQueue(llqMain, _llq_queue());
+                       if (err != kDNSServiceErr_NoError) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("DNSServiceSetDispatchQueue() failed, error = %d"),
+                                     err);
+                               DNSServiceRefDeallocate(llqMain);
+                               llqMain = NULL;
 
-static Boolean
-enqueueAsyncDNSRetry(SCNetworkReachabilityRef  target)
-{
-       int64_t                         delay;
-       dispatch_source_t               source;
-       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+                               targetPrivate->llqActive = FALSE;
 
-       source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
-                                       0,
-                                       0,
-                                       dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
-       if (source == NULL) {
-               SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability retry dispatch_source_create() failed"));
-               return FALSE;
-       }
+                               MUTEX_UNLOCK(&targetPrivate->lock);
+                               CFRelease(target);
+                               return;
+                       }
+               }
 
-       // retain the target ... and release it when the [timer] source is released
-       CFRetain(target);
-       dispatch_set_context(source, (void *)target);
-       dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease);
+               // start a long-lived-query for this target
 
-       dispatch_source_set_event_handler(source, ^(void) {
-               __SCNetworkReachabilityPerformInline(target, TRUE);
-       });
+               targetPrivate->llqTarget = llqMain;
+               err = DNSServiceGetAddrInfo(&targetPrivate->llqTarget,          // sdRef
+                                           kDNSServiceFlagsReturnIntermediates // flags
+                                           | kDNSServiceFlagsShareConnection,
+                                           targetPrivate->if_index,            // interfaceIndex
+                                           0,                                  // protocol
+                                           targetPrivate->name,                // hostname
+                                           _llq_callback,                      // callback
+                                           (void *)target);                    // context
+               if (err != kDNSServiceErr_NoError) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("DNSServiceGetAddrInfo() failed, error = %d"),
+                             err);
+                       targetPrivate->llqTarget = NULL;
+                       if (llqCount == 0) {
+                               // if this was the first request
+                               DNSServiceRefDeallocate(llqMain);
+                               llqMain = NULL;
+                       }
 
-       // start a one-shot timer
-       delay = targetPrivate->dnsRetryCount * EAI_NONAME_RETRY_DELAY_USEC * NSEC_PER_USEC;
-       dispatch_source_set_timer(source,
-                                 dispatch_time(DISPATCH_TIME_NOW, delay),      // start
-                                 0,                                            // interval
-                                 10 * NSEC_PER_MSEC);                          // leeway
+                       targetPrivate->llqActive = FALSE;
+
+                       MUTEX_UNLOCK(&targetPrivate->lock);
+                       CFRelease(target);
+                       return;
+               }
+
+               llqCount++;
+
+               // if case we don't get any callbacks from our long-lived-query (this
+               // could happen if the DNS servers do not respond), we start a timer
+               // to ensure that we fire off at least one reachability callback.
+
+               source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
+                                               0,
+                                               0,
+                                               _llq_queue());
+               if (source != NULL) {
+                       // retain the target ... and release it when the [timer] source is released
+                       CFRetain(target);
+                       dispatch_set_context(source, (void *)target);
+                       dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease);
+
+                       dispatch_source_set_event_handler(source, ^(void) {
+                               _llq_callback(NULL,                     // sdRef
+                                             0,                        // flags
+                                             0,                        // interfaceIndex
+                                             kDNSServiceErr_Timeout,   // errorCode
+                                             NULL,                     // hostname
+                                             NULL,                     // address
+                                             0,                        // ttl
+                                             (void *)target);          // context
+                       });
+
+                       dispatch_source_set_timer(source,
+                                                 dispatch_time(DISPATCH_TIME_NOW,
+                                                               LLQ_TIMEOUT_NSEC),      // start
+                                                 0,                                    // interval
+                                                 10 * NSEC_PER_MSEC);                  // leeway
+
+                       targetPrivate->llqTimer = source;
+                       dispatch_resume(source);
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("SCNetworkReachability llq dispatch_source_create(no-reply) failed"));
+               }
 
-       targetPrivate->dnsRetry = source;
-       dispatch_resume(source);
+               MUTEX_UNLOCK(&targetPrivate->lock);
+               return;
+       });
 
        return TRUE;
 }
 
 
 static void
-dequeueAsyncDNSRetry(SCNetworkReachabilityRef  target)
+dequeueLongLivedQuery(SCNetworkReachabilityRef target)
 {
+       DNSServiceRef                   sdRef;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       if (targetPrivate->dnsRetry != NULL) {
-               dispatch_source_cancel(targetPrivate->dnsRetry);
-               dispatch_release(targetPrivate->dnsRetry);
-               targetPrivate->dnsRetry = NULL;
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       // terminate the [target] llq timer
+       if (targetPrivate->llqTimer != NULL) {
+               dispatch_source_cancel(targetPrivate->llqTimer);
+               dispatch_release(targetPrivate->llqTimer);
+               targetPrivate->llqTimer = NULL;
+       }
+
+       // terminate the [target] long lived query
+       sdRef = targetPrivate->llqTarget;
+       targetPrivate->llqTarget = NULL;
+
+       // mark the long lived query NOT active
+       targetPrivate->llqActive = FALSE;
+
+       if (sdRef != NULL) {
+               dispatch_async(_llq_queue(), ^{
+                       DNSServiceRefDeallocate(sdRef);
+                       CFRelease(target);
+
+                       llqCount--;
+                       if (llqCount == 0) {
+                               // if no more queries active
+                               DNSServiceRefDeallocate(llqMain);
+                               llqMain = NULL;
+                       }
+               });
        }
 
        return;
@@ -3391,11 +4353,11 @@ __SCNetworkReachabilityOnDemandCheckCallback(SCNetworkReachabilityRef   onDemandSe
        SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)info;
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       pthread_mutex_lock(&targetPrivate->lock);
+       MUTEX_LOCK(&targetPrivate->lock);
 
        if (!targetPrivate->scheduled) {
                // if not currently scheduled
-               pthread_mutex_unlock(&targetPrivate->lock);
+               MUTEX_UNLOCK(&targetPrivate->lock);
                return;
        }
 
@@ -3403,7 +4365,7 @@ __SCNetworkReachabilityOnDemandCheckCallback(SCNetworkReachabilityRef     onDemandSe
              targetPrivate->log_prefix);
        __SCNetworkReachabilityPerform(target);
 
-       pthread_mutex_unlock(&targetPrivate->lock);
+       MUTEX_UNLOCK(&targetPrivate->lock);
 
        return;
 }
@@ -3423,6 +4385,8 @@ __SCNetworkReachabilityOnDemandCheck(ReachabilityStoreInfoRef     store_info,
        SCDynamicStoreRef               store;
        SCNetworkReachabilityPrivateRef targetPrivate           = (SCNetworkReachabilityPrivateRef)target;
 
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
 //     SCLog(_sc_debug, LOG_INFO,
 //           CFSTR("%s__SCNetworkReachabilityOnDemandCheck %s"),
 //           targetPrivate->log_prefix,
@@ -3442,9 +4406,9 @@ __SCNetworkReachabilityOnDemandCheck(ReachabilityStoreInfoRef     store_info,
                                                           &onDemandServiceID,
                                                           &onDemandStatus,
                                                           &onDemandRemoteAddress);
-       if (store_info->store != store) {
+       if ((store_info->store == NULL) && (store != NULL)) {
+               // if an SCDynamicStore session was added, keep it
                store_info->store = store;
-               store_info->storeAdded = TRUE;
        }
        if (!_SC_CFEqual(targetPrivate->onDemandRemoteAddress, onDemandRemoteAddress) ||
            !_SC_CFEqual(targetPrivate->onDemandServiceID, onDemandServiceID)) {
@@ -3494,7 +4458,10 @@ __SCNetworkReachabilityOnDemandCheck(ReachabilityStoreInfoRef    store_info,
                                                                    &kCFTypeDictionaryKeyCallBacks,
                                                                    &kCFTypeDictionaryValueCallBacks);
                                CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, onDemandRemoteAddress);
-                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionConnectionOnDemandByPass, kCFBooleanTrue);
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionConnectionOnDemandBypass, kCFBooleanTrue);
+#ifdef HAVE_REACHABILITY_SERVER
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
+#endif // HAVE_REACHABILITY_SERVER
                                targetPrivate->onDemandServer = SCNetworkReachabilityCreateWithOptions(NULL, options);
                                CFRelease(options);
 
@@ -3666,13 +4633,40 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef        store_info,
        ReachabilityInfo                my_info         = NOT_REACHABLE;
        Boolean                         ok              = TRUE;
 
-       *reach_info = NOT_REACHABLE;
+       MUTEX_ASSERT_HELD(&targetPrivate->lock);
+
+       _reach_set(reach_info, &NOT_REACHABLE, reach_info->cycle);
 
        if (!isA_SCNetworkReachability(target)) {
                _SCErrorSet(kSCStatusInvalidArgument);
                return FALSE;
        }
 
+#ifdef HAVE_REACHABILITY_SERVER
+       if (!targetPrivate->serverBypass) {
+               if (!targetPrivate->serverActive) {
+                       ok = __SCNetworkReachabilityServer_targetAdd(target);
+                       if (!ok) {
+                               targetPrivate->serverBypass = TRUE;
+                       }
+               }
+
+               if (targetPrivate->serverActive) {
+                       ok = __SCNetworkReachabilityServer_targetStatus(target);
+                       if (!ok) {
+                               SCLog(TRUE, LOG_DEBUG,
+                                     CFSTR("__SCNetworkReachabilityGetFlags _targetStatus() failed"));
+                               _SCErrorSet(kSCStatusFailed);
+                               goto done;
+                       }
+
+                       targetPrivate->cycle = targetPrivate->serverInfo.cycle;
+                       _reach_set(&my_info, &targetPrivate->serverInfo, targetPrivate->cycle);
+                       goto done;
+               }
+       }
+#endif // HAVE_REACHABILITY_SERVER
+
        switch (targetPrivate->type) {
                case reachabilityTypeAddress :
                case reachabilityTypeAddressPair : {
@@ -3729,6 +4723,7 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef  store_info,
                        struct timeval                  dnsQueryEnd;
                        int                             error;
                        SCNetworkReachabilityFlags      ns_flags;
+                       uint32_t                        ns_if_index;
                        struct addrinfo                 *res;
 
                        addresses = (CFMutableArrayRef)SCNetworkReachabilityCopyResolvedAddress(target, &error);
@@ -3737,6 +4732,9 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef  store_info,
                                if (!async) {
                                        /* if not an async request */
                                        goto checkResolvedAddress;
+                               } else if (targetPrivate->llqActive) {
+                                       /* if long-lived-query active */
+                                       goto checkResolvedAddress;
                                } else if ((targetPrivate->dnsMP == MACH_PORT_NULL) && !targetPrivate->needResolve) {
                                        struct timeval          elapsed;
                                        const struct timeval    retry_limit     = { EAI_NONAME_RETRY_LIMIT_USEC / USEC_PER_SEC,
@@ -3844,7 +4842,6 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef  store_info,
                                              targetPrivate->serv != NULL ? targetPrivate->serv : "");
 
                                        enqueueAsyncDNSRetry(target);
-
                                        break;
                                }
                        }
@@ -3870,6 +4867,8 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef  store_info,
                                                             targetPrivate->name,
                                                             targetPrivate->serv,
                                                             targetPrivate->if_index,
+                                                            &ns_if_index,
+                                                            NULL,
                                                             targetPrivate->log_prefix);
                        if (!ok) {
                                /* if we could not get DNS server info */
@@ -3914,11 +4913,19 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef        store_info,
                                break;
                        }
 
+                       if (targetPrivate->resolverBypass) {
+                               /* if we are not resolving the name,
+                                * set the flags of the resolvers */
+                               my_info.flags = ns_flags;
+                               my_info.if_index = ns_if_index;
+                               break;
+                       }
+
                        if (async) {
                                /* for async requests we return the last known status */
                                my_info = targetPrivate->info;
 
-                               if (targetPrivate->dnsPort != NULL) {
+                               if (targetPrivate->dnsMP != MACH_PORT_NULL) {
                                        /* if request already in progress */
                                        SCLog(_sc_debug, LOG_INFO,
                                              CFSTR("%swaiting for DNS reply"),
@@ -3935,6 +4942,37 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info,
                                        break;
                                }
 
+                               if (targetPrivate->llqActive) {
+                                       /* if long-lived-query active */
+                                       SCLog(_sc_debug, LOG_INFO,
+                                             CFSTR("%swaiting for DNS updates"),
+                                             targetPrivate->log_prefix);
+                                       if ((addresses != NULL) || (error != NETDB_SUCCESS)) {
+                                               /* updated reachability based on the previous reply */
+                                               goto checkResolvedAddress;
+                                       }
+                                       break;
+                               }
+
+                               if (!targetPrivate->llqBypass) {
+                                       SCLog(_sc_debug, LOG_INFO,
+                                             CFSTR("%sstart long-lived DNS query for %s%s%s%s%s"),
+                                             targetPrivate->log_prefix,
+                                             targetPrivate->name != NULL ? "name = " : "",
+                                             targetPrivate->name != NULL ? targetPrivate->name : "",
+                                             targetPrivate->name != NULL && targetPrivate->serv != NULL ? ", " : "",
+                                             targetPrivate->serv != NULL ? "serv = " : "",
+                                             targetPrivate->serv != NULL ? targetPrivate->serv : "");
+
+                                       /*
+                                        * initiate an long-lived DNS query
+                                        */
+                                       if (enqueueLongLivedQuery(target)) {
+                                               /* request initiated */
+                                               break;
+                                       }
+                               }
+
                                SCLog(_sc_debug, LOG_INFO,
                                      CFSTR("%sstart DNS query for %s%s%s%s%s"),
                                      targetPrivate->log_prefix,
@@ -3947,13 +4985,13 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef        store_info,
                                /*
                                 * initiate an async DNS query
                                 */
-                               if (!startAsyncDNSQuery(target)) {
-                                       /* if we could not initiate the request, process error */
-                                       goto checkResolvedAddress;
+                               if (startAsyncDNSQuery(target)) {
+                                       /* request initiated */
+                                       break;
                                }
 
-                               /* request initiated */
-                               break;
+                               /* if we could not initiate the request, process error */
+                               goto checkResolvedAddress;
                        }
 
                        SCLog(_sc_debug, LOG_INFO,
@@ -3990,7 +5028,7 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef  store_info,
 
                        __dns_query_end(target,
                                         ((error == 0) && (res != NULL)),       // if successful query
-                                        FALSE,                                 // sync
+                                        dns_query_sync,                        // sync
                                         &dnsQueryStart,                        // start time
                                         &dnsQueryEnd);                         // end time
 
@@ -4094,7 +5132,7 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef  store_info,
 
     done:
 
-       *reach_info = my_info;
+       _reach_set(reach_info, &my_info, targetPrivate->cycle);
 
     error :
 
@@ -4102,6 +5140,47 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info,
        return ok;
 }
 
+int
+SCNetworkReachabilityGetInterfaceIndex(SCNetworkReachabilityRef        target)
+{
+       SCNetworkReachabilityFlags      flags;
+       int                             if_index        = -1;
+       Boolean                         ok              = TRUE;
+       ReachabilityStoreInfo           store_info;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       if (!isA_SCNetworkReachability(target)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return if_index;
+       }
+
+       ReachabilityStoreInfo_init(&store_info);
+
+       MUTEX_LOCK(&targetPrivate->lock);
+
+       if (targetPrivate->scheduled) {
+               // if being watched, return the last known (and what should be current) status
+               flags = targetPrivate->info.flags & ~kSCNetworkReachabilityFlagsFirstResolvePending;
+               goto done;
+       }
+
+
+       ok = __SCNetworkReachabilityGetFlags(&store_info, target, &targetPrivate->info, FALSE);
+       flags = targetPrivate->info.flags & ~kSCNetworkReachabilityFlagsFirstResolvePending;
+
+    done :
+
+       /* Only return the if_index if the connection is reachable not for reachable connection
+        * required etc ... */
+       if (ok && rankReachability(flags) == 2) {
+               if_index = targetPrivate->info.if_index;
+       }
+
+       MUTEX_UNLOCK(&targetPrivate->lock);
+       ReachabilityStoreInfo_free(&store_info);
+       return if_index;
+}
+
 
 Boolean
 SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef         target,
@@ -4116,8 +5195,9 @@ SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef            target,
                return FALSE;
        }
 
-       initReachabilityStoreInfo(&store_info);
-       pthread_mutex_lock(&targetPrivate->lock);
+       ReachabilityStoreInfo_init(&store_info);
+
+       MUTEX_LOCK(&targetPrivate->lock);
 
        if (targetPrivate->scheduled) {
                // if being watched, return the last known (and what should be current) status
@@ -4131,8 +5211,8 @@ SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef            target,
 
     done :
 
-       pthread_mutex_unlock(&targetPrivate->lock);
-       freeReachabilityStoreInfo(&store_info);
+       MUTEX_UNLOCK(&targetPrivate->lock);
+       ReachabilityStoreInfo_free(&store_info);
        return ok;
 }
 
@@ -4270,6 +5350,9 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef     store)
 #endif // TARGET_OS_IPHONE
 
 
+       // SCDynamicStore key to force posting a reachability change
+       CFArrayAppendValue(keys, SCNETWORKREACHABILITY_TRIGGER_KEY);
+
        (void)SCDynamicStoreSetNotificationKeys(store, keys, patterns);
        CFRelease(keys);
        CFRelease(patterns);
@@ -4278,6 +5361,20 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef    store)
 }
 
 
+static dispatch_queue_t
+_hn_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create("SCNetworkReachabilty.changes", NULL);
+       });
+
+       return q;
+}
+
+
 static void
 __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store,
                                     CFArrayRef         changedKeys,
@@ -4288,9 +5385,12 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef   store,
 #endif // !TARGET_OS_IPHONE
        Boolean                 dnsConfigChanged        = FALSE;
        CFIndex                 i;
+       Boolean                 forcedChange            = FALSE;
        CFStringRef             key;
-       CFIndex                 nChanges                = CFArrayGetCount(changedKeys);
+       CFIndex                 nChanges;
+       CFIndex                 nGlobals                = 0;
        CFIndex                 nTargets;
+       Boolean                 networkConfigChanged    = FALSE;
        struct timeval          now;
 #if    !TARGET_OS_IPHONE
        Boolean                 powerStatusChanged      = FALSE;
@@ -4298,15 +5398,25 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef  store,
        ReachabilityStoreInfo   store_info;
        const void *            targets_q[N_QUICK];
        const void **           targets                 = targets_q;
+       __block CFSetRef        watchers                = NULL;
 
+       nChanges = CFArrayGetCount(changedKeys);
        if (nChanges == 0) {
                /* if no changes */
                return;
        }
 
-       pthread_mutex_lock(&hn_lock);
+       /* "something" changed, start fresh */
+       ReachabilityStoreInfo_save(NULL);
+
+       dispatch_sync(_hn_queue(), ^{
+               /* grab the currently watched targets */
+               if (hn_targets != NULL) {
+                       watchers = CFSetCreateCopy(NULL, hn_targets);
+               }
+       });
 
-       nTargets = (hn_targets != NULL) ? CFSetGetCount(hn_targets) : 0;
+       nTargets = (watchers != NULL) ? CFSetGetCount(watchers) : 0;
        if (nTargets == 0) {
                /* if no addresses being monitored */
                goto done;
@@ -4322,6 +5432,8 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef    store,
        if (CFArrayContainsValue(changedKeys, CFRangeMake(0, nChanges), key)) {
                CFNumberRef     num;
 
+               nGlobals++;
+
                num = SCDynamicStoreCopyValue(store, key);
                if (num != NULL) {
                        if (isA_CFNumber(num) &&
@@ -4356,10 +5468,20 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef  store,
                                                         kSCDynamicStoreDomainState,
                                                         kSCEntNetDNS);
        if (CFArrayContainsValue(changedKeys, CFRangeMake(0, nChanges), key)) {
+               nGlobals++;
                dnsConfigChanged = TRUE;        /* the DNS server(s) have changed */
        }
        CFRelease(key);
 
+       if (CFArrayContainsValue(changedKeys, CFRangeMake(0, nChanges), SCNETWORKREACHABILITY_TRIGGER_KEY)) {
+               nGlobals++;
+               forcedChange = TRUE;            /* an SCDynamicStore driven "network" change */
+       }
+
+       if (nChanges > nGlobals) {
+               networkConfigChanged = TRUE;
+       }
+
        if (_sc_debug) {
                unsigned int            changes                 = 0;
                static const char       *change_strings[]       = {
@@ -4375,7 +5497,7 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef    store,
                        "DNS and power ",
                        "network, DNS, and power ",
 
-                       // with no "power" status change (including CPU "on")
+                       // with "power" status change (including CPU "on")
                        "power* ",
                        "network and power* ",
                        "DNS and power* ",
@@ -4390,42 +5512,51 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef  store,
                        if (cpuStatusChanged) {
                                changes += PWR;
                        }
-                       nChanges -= 1;
                }
 #endif // !TARGET_OS_IPHONE
 
                #define DNS     2
                if (dnsConfigChanged) {
                        changes |= DNS;
-                       nChanges -= 1;
                }
 
                #define NET     1
-               if (nChanges > 0) {
+               if (networkConfigChanged) {
                        changes |= NET;
                }
 
                SCLog(TRUE, LOG_INFO,
-                     CFSTR("process %sconfiguration change"),
+                     CFSTR("process %s%sconfiguration change"),
+                     forcedChange ? "[forced] " : "",
                      change_strings[changes]);
        }
 
-       initReachabilityStoreInfo(&store_info);
+       ReachabilityStoreInfo_init(&store_info);
 
        if (nTargets > (CFIndex)(sizeof(targets_q) / sizeof(CFTypeRef)))
                targets = CFAllocatorAllocate(NULL, nTargets * sizeof(CFTypeRef), 0);
-       CFSetGetValues(hn_targets, targets);
+       CFSetGetValues(watchers, targets);
        for (i = 0; i < nTargets; i++) {
                SCNetworkReachabilityRef        target          = targets[i];
                SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-               pthread_mutex_lock(&targetPrivate->lock);
+               MUTEX_LOCK(&targetPrivate->lock);
 
                if (dnsConfigChanged) {
                        targetPrivate->last_dns = now;
                        targetPrivate->dnsRetryCount = 0;
                }
 
+               if (networkConfigChanged) {
+                       targetPrivate->last_network = now;
+               }
+
+#if    !TARGET_OS_IPHONE
+               if (powerStatusChanged) {
+                       targetPrivate->last_power = now;
+               }
+#endif // !TARGET_OS_IPHONE
+
                if (targetPrivate->type == reachabilityTypeName) {
                        Boolean         dnsChanged      = dnsConfigChanged;
 
@@ -4438,7 +5569,7 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef    store,
                                Boolean                         ok;
 
                                /* check the reachability of the DNS servers */
-                               ok = updateReachabilityStoreInfo(&store_info, &store, AF_UNSPEC);
+                               ok = ReachabilityStoreInfo_update(&store_info, &store, AF_UNSPEC);
                                if (ok) {
                                        ok = _SC_R_checkResolverReachability(&store_info,
                                                                             &ns_flags,
@@ -4446,6 +5577,8 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef    store,
                                                                             targetPrivate->name,
                                                                             targetPrivate->serv,
                                                                             targetPrivate->if_index,
+                                                                            NULL,
+                                                                            NULL,
                                                                             targetPrivate->log_prefix);
                                }
 
@@ -4467,9 +5600,7 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef    store,
                        }
 
                        if (dnsChanged) {
-                               if (targetPrivate->dnsPort != NULL) {
-                                       mach_port_t     mp      = CFMachPortGetPort(targetPrivate->dnsPort);
-
+                               if (targetPrivate->dnsMP != MACH_PORT_NULL) {
                                        /* cancel the outstanding DNS query */
                                        SCLog(_sc_debug, LOG_INFO,
                                              CFSTR("%scancel DNS query for %s%s%s%s%s"),
@@ -4479,8 +5610,7 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef    store,
                                              targetPrivate->name != NULL && targetPrivate->serv != NULL ? ", " : "",
                                              targetPrivate->serv != NULL ? "serv = " : "",
                                              targetPrivate->serv != NULL ? targetPrivate->serv : "");
-                                       dequeueAsyncDNSQuery(target);
-                                       getaddrinfo_async_cancel(mp);
+                                       dequeueAsyncDNSQuery(target, TRUE);
                                }
 
                                if (targetPrivate->dnsRetry != NULL) {
@@ -4493,17 +5623,23 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef  store,
                        }
                }
 
-               __SCNetworkReachabilityPerform(target);
+               if (forcedChange) {
+                       targetPrivate->cycle++;
+               }
+
+               if (targetPrivate->scheduled) {
+                       __SCNetworkReachabilityPerform(target);
+               }
 
-               pthread_mutex_unlock(&targetPrivate->lock);
+               MUTEX_UNLOCK(&targetPrivate->lock);
        }
        if (targets != targets_q)       CFAllocatorDeallocate(NULL, targets);
 
-       freeReachabilityStoreInfo(&store_info);
+       ReachabilityStoreInfo_free(&store_info);
 
     done :
 
-       pthread_mutex_unlock(&hn_lock);
+       if (watchers != NULL) CFRelease(watchers);
        return;
 }
 
@@ -4548,11 +5684,13 @@ systemIsAwake(IOPMSystemPowerStateCapabilities power_capabilities)
 
 
 static void
-rlsPerform(void *info)
+reachPerform(void *info)
 {
        void                            *context_info;
        void                            (*context_release)(const void *);
+       uint64_t                        cycle;
        Boolean                         defer           = FALSE;
+       Boolean                         forced;
        Boolean                         ok;
        ReachabilityInfo                reach_info      = NOT_REACHABLE;
        SCNetworkReachabilityCallBack   rlsFunction;
@@ -4564,7 +5702,7 @@ rlsPerform(void *info)
              targetPrivate->log_prefix);
 
 
-       pthread_mutex_lock(&targetPrivate->lock);
+       MUTEX_LOCK(&targetPrivate->lock);
 
        if (targetPrivate->dnsRetry != NULL) {
                // cancel DNS retry
@@ -4573,14 +5711,14 @@ rlsPerform(void *info)
 
        if (!targetPrivate->scheduled) {
                // if not currently scheduled
-               pthread_mutex_unlock(&targetPrivate->lock);
+               MUTEX_UNLOCK(&targetPrivate->lock);
                return;
        }
 
        /* update reachability, notify if status changed */
-       initReachabilityStoreInfo(&store_info);
+       ReachabilityStoreInfo_init(&store_info);
        ok = __SCNetworkReachabilityGetFlags(&store_info, target, &reach_info, TRUE);
-       freeReachabilityStoreInfo(&store_info);
+       ReachabilityStoreInfo_free(&store_info);
        if (!ok) {
                /* if reachability status not available */
                SCLog(_sc_debug, LOG_INFO, CFSTR("%flags not available"),
@@ -4604,7 +5742,7 @@ rlsPerform(void *info)
                         * the same or "better"
                         */
                        defer = !darkWakeNotify(target);
-               } else if (__reach_equal(&targetPrivate->last_notify, &reach_info)) {
+               } else if (!__reach_changed(&targetPrivate->last_notify, &reach_info)) {
                        /*
                         * if we have already posted this change
                         */
@@ -4613,7 +5751,10 @@ rlsPerform(void *info)
        }
 #endif // !TARGET_OS_IPHONE
 
-       if (__reach_equal(&targetPrivate->info, &reach_info)) {
+       cycle = targetPrivate->cycle;
+       forced = ((cycle != 0) && (targetPrivate->info.cycle != cycle));
+
+       if (!forced && !__reach_changed(&targetPrivate->info, &reach_info)) {
                if (_sc_debug) {
                        if (targetPrivate->info.sleeping == reach_info.sleeping) {
                                SCLog(TRUE, LOG_INFO,
@@ -4635,12 +5776,12 @@ rlsPerform(void *info)
                        }
 
                }
-               pthread_mutex_unlock(&targetPrivate->lock);
+               MUTEX_UNLOCK(&targetPrivate->lock);
                return;
        }
 
        SCLog(_sc_debug, LOG_INFO,
-             CFSTR("%sflags/interface have changed (was 0x%08x/%hu%s, now 0x%08x/%hu%s)%s"),
+             CFSTR("%sflags/interface have changed (was 0x%08x/%hu%s, now 0x%08x/%hu%s)%s%s"),
              targetPrivate->log_prefix,
              targetPrivate->info.flags,
              targetPrivate->info.if_index,
@@ -4648,19 +5789,23 @@ rlsPerform(void *info)
              reach_info.flags,
              reach_info.if_index,
              reach_info.sleeping ? ", z" : "",
-             defer ? ", deferred" : "");
+             defer ? ", deferred" : "",
+             forced ? ", forced" : "");
 
        /* as needed, defer the notification */
        if (defer) {
-               pthread_mutex_unlock(&targetPrivate->lock);
+               MUTEX_UNLOCK(&targetPrivate->lock);
                return;
        }
 
        /* update flags / interface */
-       targetPrivate->info = reach_info;
+       _reach_set(&targetPrivate->info, &reach_info, cycle);
 
        /* save last notification info */
-       targetPrivate->last_notify = reach_info;
+       _reach_set(&targetPrivate->last_notify, &reach_info, cycle);
+
+       /* save last notification time */
+       (void)gettimeofday(&targetPrivate->last_push, NULL);
 
        /* callout */
        rlsFunction = targetPrivate->rlsFunction;
@@ -4672,7 +5817,7 @@ rlsPerform(void *info)
                context_release = NULL;
        }
 
-       pthread_mutex_unlock(&targetPrivate->lock);
+       MUTEX_UNLOCK(&targetPrivate->lock);
 
        if (rlsFunction != NULL) {
                (*rlsFunction)(target,
@@ -4695,7 +5840,7 @@ SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
 {
        SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target;
 
-       pthread_mutex_lock(&targetPrivate->lock);
+       MUTEX_LOCK(&targetPrivate->lock);
 
        if (targetPrivate->rlsContext.release != NULL) {
                /* let go of the current context */
@@ -4714,7 +5859,7 @@ SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
                }
        }
 
-       pthread_mutex_unlock(&targetPrivate->lock);
+       MUTEX_UNLOCK(&targetPrivate->lock);
 
        return TRUE;
 }
@@ -4741,12 +5886,9 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef      target,
 {
        SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
        Boolean                         init            = FALSE;
-       Boolean                         ok              = FALSE;
+       __block Boolean                 ok              = FALSE;
 
-       if (!onDemand) {
-               pthread_mutex_lock(&hn_lock);
-       }
-       pthread_mutex_lock(&targetPrivate->lock);
+       MUTEX_LOCK(&targetPrivate->lock);
 
        if ((targetPrivate->dispatchQueue != NULL) ||           // if we are already scheduled with a dispatch queue
            ((queue != NULL) && targetPrivate->scheduled)) {    // if we are already scheduled on a CFRunLoop
@@ -4754,53 +5896,99 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef     target,
                goto done;
        }
 
-       /* schedule the SCNetworkReachability run loop source */
-
-       if (!onDemand && (hn_store == NULL)) {
-               /*
-                * if we are not monitoring any hosts, start watching
-                */
-               if (!dns_configuration_watch()) {
-                       // if error
-                       _SCErrorSet(kSCStatusFailed);
-                       goto done;
+#ifdef HAVE_REACHABILITY_SERVER
+       if (!targetPrivate->serverBypass) {
+               if (!targetPrivate->serverActive) {
+                       ok = __SCNetworkReachabilityServer_targetAdd(target);
+                       if (!ok) {
+                               targetPrivate->serverBypass = TRUE;
+                       }
                }
 
-               hn_store = SCDynamicStoreCreate(NULL,
-                                               CFSTR("SCNetworkReachability"),
-                                               __SCNetworkReachabilityHandleChanges,
-                                               NULL);
-               if (hn_store == NULL) {
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCreate() failed"));
-                       goto done;
-               }
+               if (targetPrivate->serverActive) {
+                       if (targetPrivate->scheduled) {
+                               // if already scheduled
+                               goto watch;
+                       }
 
-               __SCNetworkReachabilityReachabilitySetNotifications(hn_store);
+                       ok = __SCNetworkReachabilityServer_targetSchedule(target);
+                       if (!ok) {
+                               SCLog(TRUE, LOG_DEBUG,
+                                     CFSTR("__SCNetworkReachabilityScheduleWithRunLoop _targetMonitor() failed"));
+                               _SCErrorSet(kSCStatusFailed);
+                               goto done;
+                       }
 
-               hn_dispatchQueue = dispatch_queue_create("com.apple.SCNetworkReachabilty.network_changes", NULL);
-               if (hn_dispatchQueue == NULL) {
-                       SCLog(TRUE, LOG_ERR, CFSTR("__SCNetworkReachabilityScheduleWithRunLoop dispatch_queue_create() failed"));
-                       _SCErrorSet(kSCStatusFailed);
-                       CFRelease(hn_store);
-                       hn_store = NULL;
-                       goto done;
+                       goto watch;
                }
-               CFRetain(hn_store);     // Note: will be released when the dispatch queue is released
-               dispatch_set_context(hn_dispatchQueue, (void *)hn_store);
-               dispatch_set_finalizer_f(hn_dispatchQueue, (dispatch_function_t)CFRelease);
+       }
+#endif // HAVE_REACHABILITY_SERVER
 
-               ok = SCDynamicStoreSetDispatchQueue(hn_store, hn_dispatchQueue);
-               if (!ok) {
-                       SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetDispatchQueue() failed"));
-                       dispatch_release(hn_dispatchQueue);
-                       hn_dispatchQueue = NULL;
-                       CFRelease(hn_store);
-                       hn_store = NULL;
-                       goto done;
+       /* schedule the SCNetworkReachability did-something-change handler */
+
+       dispatch_sync(_hn_queue(), ^{
+               ok = FALSE;
+
+               if (!onDemand && (hn_store == NULL)) {
+                       /*
+                        * if we are not monitoring any hosts, start watching
+                        */
+                       if (!dns_configuration_watch()) {
+                               // if error
+                               _SCErrorSet(kSCStatusFailed);
+                               return;
+                       }
+
+                       hn_store = SCDynamicStoreCreate(NULL,
+                                                       CFSTR("SCNetworkReachability"),
+                                                       __SCNetworkReachabilityHandleChanges,
+                                                       NULL);
+                       if (hn_store == NULL) {
+                               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCreate() failed"));
+                               dns_configuration_unwatch();
+                               return;
+                       }
+
+                       __SCNetworkReachabilityReachabilitySetNotifications(hn_store);
+
+                       hn_dispatchQueue = dispatch_queue_create("SCNetworkReachabilty.changes", NULL);
+                       if (hn_dispatchQueue == NULL) {
+                               SCLog(TRUE, LOG_ERR, CFSTR("__SCNetworkReachabilityScheduleWithRunLoop dispatch_queue_create() failed"));
+                               CFRelease(hn_store);
+                               hn_store = NULL;
+                               dns_configuration_unwatch();
+                               _SCErrorSet(kSCStatusFailed);
+                               return;
+                       }
+
+                       ok = SCDynamicStoreSetDispatchQueue(hn_store, hn_dispatchQueue);
+                       if (!ok) {
+                               SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetDispatchQueue() failed"));
+                               dispatch_release(hn_dispatchQueue);
+                               hn_dispatchQueue = NULL;
+                               CFRelease(hn_store);
+                               hn_store = NULL;
+                               dns_configuration_unwatch();
+                               return;
+                       }
+                       hn_targets = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+
+                       ReachabilityStoreInfo_enable(TRUE);
                }
-               hn_targets  = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+
+               CFSetAddValue(hn_targets, target);
+
+               ok = TRUE;
+       });
+
+       if (!ok) {
+               goto done;
        }
 
+#ifdef HAVE_REACHABILITY_SERVER
+    watch :
+#endif // HAVE_REACHABILITY_SERVER
+
        if (!targetPrivate->scheduled) {
                CFRunLoopSourceContext  context = { 0                           // version
                                                  , (void *)target              // info
@@ -4811,7 +5999,7 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef       target,
                                                  , CFHash                      // hash
                                                  , NULL                        // schedule
                                                  , NULL                        // cancel
-                                                 , rlsPerform                  // perform
+                                                 , reachPerform                // perform
                                                  };
 
                if (runLoop != NULL) {
@@ -4819,16 +6007,53 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef     target,
                        targetPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
                }
 
-               targetPrivate->scheduled = TRUE;
                if (targetPrivate->type == reachabilityTypeName) {
+                       /*
+                        * we're now scheduled so let's ensure that we
+                        * are starting with a clean slate before we
+                        * resolve the name
+                        */
+                       if (targetPrivate->resolvedAddress != NULL) {
+                               CFRelease(targetPrivate->resolvedAddress);
+                               targetPrivate->resolvedAddress = NULL;
+                       }
+                       targetPrivate->resolvedAddressError = NETDB_SUCCESS;
                        targetPrivate->needResolve = TRUE;
+                       _reach_set(&targetPrivate->info, &NOT_REACHABLE, targetPrivate->info.cycle);
+                       targetPrivate->info.flags |= kSCNetworkReachabilityFlagsFirstResolvePending;
+#ifdef HAVE_REACHABILITY_SERVER
+                       _reach_set(&targetPrivate->serverInfo, &NOT_REACHABLE, targetPrivate->serverInfo.cycle);
+                       targetPrivate->serverInfo.flags |= kSCNetworkReachabilityFlagsFirstResolvePending;
+#endif // HAVE_REACHABILITY_SERVER
                }
+
+               targetPrivate->scheduled = TRUE;
+
                init = TRUE;
        }
 
        if (queue != NULL) {
+               // retain dispatch queue
+               dispatch_retain(queue);
                targetPrivate->dispatchQueue = queue;
-               dispatch_retain(targetPrivate->dispatchQueue);
+
+               //
+               // We've taken a reference to the client's dispatch_queue and we
+               // want to hold on to that reference until we've processed any/all
+               // notifications.  To facilitate this we create a group, dispatch
+               // any notification blocks to via that group, and when the caller
+               // has told us to stop the notifications (unschedule) we wait for
+               // the group to empty and use the group's finalizer to release
+               // our reference to the client's queue.
+               //
+
+               // make sure that we have group to track any async requests
+               targetPrivate->dispatchGroup = dispatch_group_create();
+
+               // retain the target ... and release it when the group is released
+               CFRetain(target);
+               dispatch_set_context(targetPrivate->dispatchGroup, (void *)target);
+               dispatch_set_finalizer_f(targetPrivate->dispatchGroup, (dispatch_function_t)CFRelease);
        } else {
                if (!_SC_isScheduled(NULL, runLoop, runLoopMode, targetPrivate->rlList)) {
                        /*
@@ -4838,7 +6063,7 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef       target,
                        CFRunLoopAddSource(runLoop, targetPrivate->rls, runLoopMode);
 
                        if (targetPrivate->dnsRLS != NULL) {
-                               /* if we have an active async DNS query too */
+                               // if we have an active async DNS query too
                                CFRunLoopAddSource(runLoop, targetPrivate->dnsRLS, runLoopMode);
                        }
                }
@@ -4846,8 +6071,6 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef       target,
                _SC_schedule(target, runLoop, runLoopMode, targetPrivate->rlList);
        }
 
-       CFSetAddValue(hn_targets, target);
-
        if (init) {
                ReachabilityInfo        reach_info      = NOT_REACHABLE;
                ReachabilityStoreInfo   store_info;
@@ -4856,20 +6079,26 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef     target,
                 * if we have yet to schedule SC notifications for this address
                 * - initialize current reachability status
                 */
-               initReachabilityStoreInfo(&store_info);
+               ReachabilityStoreInfo_init(&store_info);
                if (__SCNetworkReachabilityGetFlags(&store_info, target, &reach_info, TRUE)) {
                        /*
                         * if reachability status available
                         * - set flags
                         * - schedule notification to report status via callback
                         */
-                       targetPrivate->info = reach_info;
+#ifdef HAVE_REACHABILITY_SERVER
+                       reach_info.flags |= (targetPrivate->info.flags & kSCNetworkReachabilityFlagsFirstResolvePending);
+#endif // HAVE_REACHABILITY_SERVER
+                       _reach_set(&targetPrivate->info, &reach_info, targetPrivate->cycle);
                        __SCNetworkReachabilityPerform(target);
                } else {
                        /* if reachability status not available, async lookup started */
-                       targetPrivate->info = NOT_REACHABLE;
+                       _reach_set(&targetPrivate->info, &NOT_REACHABLE, targetPrivate->cycle);
+#ifdef HAVE_REACHABILITY_SERVER
+                       _reach_set(&targetPrivate->serverInfo, &NOT_REACHABLE, targetPrivate->cycle);
+#endif // HAVE_REACHABILITY_SERVER
                }
-               freeReachabilityStoreInfo(&store_info);
+               ReachabilityStoreInfo_free(&store_info);
        }
 
        if (targetPrivate->onDemandServer != NULL) {
@@ -4883,10 +6112,7 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef      target,
 
     done :
 
-       pthread_mutex_unlock(&targetPrivate->lock);
-       if (!onDemand) {
-               pthread_mutex_unlock(&hn_lock);
-       }
+       MUTEX_UNLOCK(&targetPrivate->lock);
        return ok;
 }
 
@@ -4897,14 +6123,16 @@ __SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef   target,
                                             CFStringRef                runLoopMode,
                                             Boolean                    onDemand)
 {
-       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+       dispatch_group_t                drainGroup      = NULL;
+       dispatch_queue_t                drainQueue      = NULL;
        CFIndex                         n               = 0;
        Boolean                         ok              = FALSE;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
 
-       if (!onDemand) {
-               pthread_mutex_lock(&hn_lock);
-       }
-       pthread_mutex_lock(&targetPrivate->lock);
+       // hold a reference while we unschedule
+       CFRetain(target);
+
+       MUTEX_LOCK(&targetPrivate->lock);
 
        if (((runLoop == NULL) && (targetPrivate->dispatchQueue == NULL)) ||    // if we should be scheduled on a dispatch queue (but are not)
            ((runLoop != NULL) && (targetPrivate->dispatchQueue != NULL))) {    // if we should be scheduled on a CFRunLoop (but are not)
@@ -4918,11 +6146,17 @@ __SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef   target,
                goto done;
        }
 
-       // first, unschedule the target specific sources
+       // unschedule the target specific sources
        if (targetPrivate->dispatchQueue != NULL) {
                if (targetPrivate->onDemandServer != NULL) {
                        __SCNetworkReachabilityUnscheduleFromRunLoop(targetPrivate->onDemandServer, NULL, NULL, TRUE);
                }
+
+               // save dispatchQueue, release reference when we've queue'd blocks complete, allow re-scheduling
+               drainGroup = targetPrivate->dispatchGroup;
+               targetPrivate->dispatchGroup = NULL;
+               drainQueue = targetPrivate->dispatchQueue;
+               targetPrivate->dispatchQueue = NULL;
        } else {
                if (!_SC_unschedule(target, runLoop, runLoopMode, targetPrivate->rlList, FALSE)) {
                        // if not currently scheduled
@@ -4956,51 +6190,82 @@ __SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef   target,
        }
 
        if (n == 0) {
+#ifdef HAVE_REACHABILITY_SERVER
+               //
+               // Cancel our request for server monitoring
+               //
+               if (targetPrivate->serverActive) {
+                       ok = __SCNetworkReachabilityServer_targetUnschedule(target);
+                       if (!ok) {
+                               SCLog(TRUE, LOG_DEBUG,
+                                     CFSTR("__SCNetworkReachabilityUnscheduleFromRunLoop _targetMonitor() failed"));
+                               _SCErrorSet(kSCStatusFailed);
+                       }
+               }
+#endif // HAVE_REACHABILITY_SERVER
+
                // if *all* notifications have been unscheduled
                targetPrivate->scheduled = FALSE;
+       }
 
-               if (!onDemand) {
-                       CFSetRemoveValue(hn_targets, target);   // cleanup notification resources
-               }
-
-               if (targetPrivate->dnsPort != NULL) {
-                       mach_port_t     mp      = CFMachPortGetPort(targetPrivate->dnsPort);
+#ifdef HAVE_REACHABILITY_SERVER
+       if (targetPrivate->serverActive) {
+               goto unwatch;
+       }
+#endif // HAVE_REACHABILITY_SERVER
 
+       if (n == 0) {
+               if (targetPrivate->dnsMP != MACH_PORT_NULL) {
                        // if we have an active async DNS query
-                       dequeueAsyncDNSQuery(target);
-                       getaddrinfo_async_cancel(mp);
+                       dequeueAsyncDNSQuery(target, TRUE);
                }
 
                if (targetPrivate->dnsRetry != NULL) {
                        // if we have an outstanding DNS retry
                        dequeueAsyncDNSRetry(target);
                }
-       }
 
-       if (runLoop == NULL) {
-               dispatch_release(targetPrivate->dispatchQueue);
-               targetPrivate->dispatchQueue = NULL;
-       }
+               if (targetPrivate->llqActive) {
+                       // if we have a long-lived-query
+                       dequeueLongLivedQuery(target);
+               }
 
-       n = CFSetGetCount(hn_targets);
-       if (n == 0) {
-               // if we are no longer monitoring any targets
-               SCDynamicStoreSetDispatchQueue(hn_store, NULL);
-               dispatch_release(hn_dispatchQueue);
-               hn_dispatchQueue = NULL;
-               CFRelease(hn_store);
-               hn_store = NULL;
-               CFRelease(hn_targets);
-               hn_targets = NULL;
+               dispatch_sync(_hn_queue(), ^{
+                       CFSetRemoveValue(hn_targets, target);
 
-               /*
-                * until we start monitoring again, ensure that
-                * any resources associated with tracking the
-                * DNS configuration have been released.
-                */
-               dns_configuration_unwatch();
+                       if (onDemand) {
+                               return;
+                       }
+
+                       if (CFSetGetCount(hn_targets) > 0) {
+                               return;
+                       }
+
+                       // if we are no longer monitoring any targets
+                       SCDynamicStoreSetDispatchQueue(hn_store, NULL);
+                       dispatch_release(hn_dispatchQueue);
+                       hn_dispatchQueue = NULL;
+                       CFRelease(hn_store);
+                       hn_store = NULL;
+                       CFRelease(hn_targets);
+                       hn_targets = NULL;
+
+                       ReachabilityStoreInfo_enable(FALSE);
+                       ReachabilityStoreInfo_save(NULL);
+
+                       /*
+                        * until we start monitoring again, ensure that
+                        * any resources associated with tracking the
+                        * DNS configuration have been released.
+                        */
+                       dns_configuration_unwatch();
+               });
        }
 
+#ifdef HAVE_REACHABILITY_SERVER
+    unwatch :
+#endif // HAVE_REACHABILITY_SERVER
+
        SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%sunscheduled"),
              targetPrivate->log_prefix);
 
@@ -5008,10 +6273,19 @@ __SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef   target,
 
     done :
 
-       pthread_mutex_unlock(&targetPrivate->lock);
-       if (!onDemand) {
-               pthread_mutex_unlock(&hn_lock);
+       MUTEX_UNLOCK(&targetPrivate->lock);
+
+       if (drainGroup != NULL) {
+               dispatch_group_notify(drainGroup, __SCNetworkReachability_concurrent_queue(), ^{
+                       // release group/queue references
+                       dispatch_release(drainQueue);
+                       dispatch_release(drainGroup);   // releases our target reference
+               });
        }
+
+       // release our reference
+       CFRelease(target);
+
        return ok;
 }
 
diff --git a/SystemConfiguration.fproj/SCNetworkReachabilityInternal.h b/SystemConfiguration.fproj/SCNetworkReachabilityInternal.h
new file mode 100644 (file)
index 0000000..f0caeaa
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCNETWORKREACHABILITYINTERNAL_H
+#define _SCNETWORKREACHABILITYINTERNAL_H
+
+#include <Availability.h>
+#include <TargetConditionals.h>
+#include <sys/cdefs.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFRuntime.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <dispatch/dispatch.h>
+
+#include <dns_sd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#if    ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) && !TARGET_IPHONE_SIMULATOR
+#define        HAVE_REACHABILITY_SERVER
+#include <xpc/xpc.h>
+#endif // ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) && !TARGET_IPHONE_SIMULATOR
+
+
+#pragma mark -
+#pragma mark SCNetworkReachability
+
+
+#define kSCNetworkReachabilityFlagsFirstResolvePending (1<<31)
+
+
+typedef        enum { NO = 0, YES, UNKNOWN }   lazyBoolean;
+
+
+typedef enum {
+       reachabilityTypeAddress,
+       reachabilityTypeAddressPair,
+       reachabilityTypeName
+} ReachabilityAddressType;
+
+
+typedef struct {
+       uint64_t                        cycle;
+       SCNetworkReachabilityFlags      flags;
+       unsigned int                    if_index;
+       char                            if_name[IFNAMSIZ];
+       Boolean                         sleeping;
+} ReachabilityInfo;
+
+
+typedef struct {
+
+       /* base CFType information */
+       CFRuntimeBase                   cfBase;
+
+       /* lock */
+       pthread_mutex_t                 lock;
+
+       /* address type */
+       ReachabilityAddressType         type;
+
+       /* target host name */
+       const char                      *name;
+       const char                      *serv;
+       struct addrinfo                 hints;
+       Boolean                         needResolve;
+       CFArrayRef                      resolvedAddress;        /* CFArray[CFData] */
+       int                             resolvedAddressError;
+
+       /* [scoped routing] interface constraints */
+       unsigned int                    if_index;
+       char                            if_name[IFNAMSIZ];
+
+       /* local & remote addresses */
+       struct sockaddr                 *localAddress;
+       struct sockaddr                 *remoteAddress;
+
+       /* current reachability flags */
+       uint64_t                        cycle;
+       ReachabilityInfo                info;
+       ReachabilityInfo                last_notify;
+
+       /* run loop source, callout, context, rl scheduling info */
+       Boolean                         scheduled;
+       CFRunLoopSourceRef              rls;
+       SCNetworkReachabilityCallBack   rlsFunction;
+       SCNetworkReachabilityContext    rlsContext;
+       CFMutableArrayRef               rlList;
+
+       dispatch_group_t                dispatchGroup;
+       dispatch_queue_t                dispatchQueue;          // SCNetworkReachabilitySetDispatchQueue
+
+       /* [async] DNS query info */
+       Boolean                         haveDNS;
+       mach_port_t                     dnsMP;                  // != MACH_PORT_NULL (if active)
+       CFMachPortRef                   dnsPort;                // for CFRunLoop queries
+       CFRunLoopSourceRef              dnsRLS;                 // for CFRunLoop queries
+       dispatch_source_t               dnsSource;              // for dispatch queries
+       struct timeval                  dnsQueryStart;
+       struct timeval                  dnsQueryEnd;
+       dispatch_source_t               dnsRetry;               // != NULL if DNS retry request queued
+       int                             dnsRetryCount;          // number of retry attempts
+
+       /* [async] processing info */
+       struct timeval                  last_dns;
+       struct timeval                  last_network;
+#if    !TARGET_OS_IPHONE
+       struct timeval                  last_power;
+#endif // !TARGET_OS_IPHONE
+       struct timeval                  last_push;
+
+       /* on demand info */
+       Boolean                         onDemandBypass;
+       CFStringRef                     onDemandName;
+       CFStringRef                     onDemandRemoteAddress;
+       SCNetworkReachabilityRef        onDemandServer;
+       CFStringRef                     onDemandServiceID;
+
+
+       Boolean                         llqActive;
+       Boolean                         llqBypass;
+       DNSServiceRef                   llqTarget;
+       dispatch_source_t               llqTimer;               // != NULL while waiting for first callback
+
+#ifdef HAVE_REACHABILITY_SERVER
+       /* SCNetworkReachability server "client" info */
+       Boolean                         serverActive;
+       Boolean                         serverBypass;
+       Boolean                         serverScheduled;
+       ReachabilityInfo                serverInfo;
+
+       /* SCNetworkReachability server "server" info */
+       CFDataRef                       serverDigest;
+       dispatch_group_t                serverGroup;
+       Boolean                         serverInfoValid;
+       unsigned int                    serverQueryActive;      // 0 == no query active, else # waiting on group
+       dispatch_queue_t                serverQueue;
+       unsigned int                    serverReferences;       // how many [client] targets
+       CFMutableDictionaryRef          serverWatchers;         // [client_id/target_id] watchers
+#endif // HAVE_REACHABILITY_SERVER
+       Boolean                         resolverBypass;         // set this flag to bypass resolving the name
+
+       /* logging */
+       char                            log_prefix[32];
+
+} SCNetworkReachabilityPrivate, *SCNetworkReachabilityPrivateRef;
+
+
+#ifdef HAVE_REACHABILITY_SERVER
+
+// ------------------------------------------------------------
+
+#pragma mark -
+#pragma mark [XPC] Reachability Server
+
+
+#define        REACH_SERVER_VERSION            20110323
+#define        REACH_SERVICE_NAME              "com.apple.SystemConfiguration.SCNetworkReachability"
+
+// ------------------------------------------------------------
+
+
+#pragma mark -
+#pragma mark [XPC] Reachability Server (client->server request)
+
+
+#define        REACH_CLIENT_PROC_NAME          "proc_name"             // string
+#define        REACH_CLIENT_TARGET_ID          "target_id"             // uint64
+
+#define        REACH_REQUEST                   "request_op"            // int64
+
+enum {
+       REACH_REQUEST_CREATE            = 0x0001,
+       REACH_REQUEST_REMOVE,
+       REACH_REQUEST_SCHEDULE,
+       REACH_REQUEST_STATUS,
+       REACH_REQUEST_UNSCHEDULE,
+       REACH_REQUEST_SNAPSHOT          = 0x0101,
+};
+
+#define        REACH_TARGET_NAME               "name"                  // string
+#define        REACH_TARGET_SERV               "serv"                  // string
+#define        REACH_TARGET_HINTS              "hints"                 // data (struct addrinfo)
+#define        REACH_TARGET_IF_INDEX           "if_index"              // int64
+#define        REACH_TARGET_IF_NAME            "if_name"               // string
+#define        REACH_TARGET_LOCAL_ADDR         "localAddress"          // data (struct sockaddr)
+#define        REACH_TARGET_REMOTE_ADDR        "remoteAddress"         // data (struct sockaddr)
+#define        REACH_TARGET_ONDEMAND_BYPASS    "onDemandBypass"        // bool
+#define REACH_TARGET_RESOLVER_BYPASS   "resolverBypass"        // bool
+
+
+#define REACH_REQUEST_REPLY            "reply"                 // int64
+#define REACH_REQUEST_REPLY_DETAIL     "reply_detail"          // string
+
+enum {
+       REACH_REQUEST_REPLY_OK          = 0x0000,
+       REACH_REQUEST_REPLY_FAILED,
+       REACH_REQUEST_REPLY_UNKNOWN,
+};
+
+
+// ------------------------------------------------------------
+
+
+#pragma mark -
+#pragma mark [XPC] Reachability Server (server->client request)
+
+
+#define        MESSAGE_NOTIFY                  "notify_op"             // int64
+
+enum {
+       MESSAGE_REACHABILITY_STATUS     = 0x1001,
+};
+
+#define REACH_STATUS_CYCLE                     "cycle"                 // uint64
+#define REACH_STATUS_FLAGS                     "flags"                 // uint64
+#define REACH_STATUS_IF_INDEX                  "if_index"              // uint64
+#define REACH_STATUS_IF_NAME                   "if_name"               // data (char if_name[IFNAMSIZ])
+#define REACH_STATUS_RESOLVED_ADDRESS          "resolvedAddress"       // array[data]
+#define REACH_STATUS_RESOLVED_ADDRESS_ERROR    "resolvedAddressError"  // int64
+#define REACH_STATUS_SLEEPING                  "sleeping"              // bool
+
+
+// ------------------------------------------------------------
+
+#endif // HAVE_REACHABILITY_SERVER
+
+
+__BEGIN_DECLS
+
+CFStringRef
+_SCNetworkReachabilityCopyTargetDescription    (SCNetworkReachabilityRef       target);
+
+CFStringRef
+_SCNetworkReachabilityCopyTargetFlags          (SCNetworkReachabilityRef       target);
+
+#ifdef HAVE_REACHABILITY_SERVER
+
+dispatch_queue_t
+__SCNetworkReachability_concurrent_queue       (void);
+
+void
+__SCNetworkReachabilityPerformNoLock           (SCNetworkReachabilityRef       target);
+
+#pragma mark -
+#pragma mark [XPC] Reachability Server (client APIs)
+
+Boolean
+_SCNetworkReachabilityServer_snapshot          (void);
+
+Boolean
+__SCNetworkReachabilityServer_targetAdd                (SCNetworkReachabilityRef       target);
+
+void
+__SCNetworkReachabilityServer_targetRemove     (SCNetworkReachabilityRef       target);
+
+Boolean
+__SCNetworkReachabilityServer_targetSchedule   (SCNetworkReachabilityRef       target);
+
+Boolean
+__SCNetworkReachabilityServer_targetStatus     (SCNetworkReachabilityRef       target);
+
+Boolean
+__SCNetworkReachabilityServer_targetUnschedule (SCNetworkReachabilityRef       target);
+
+Boolean
+__SC_checkResolverReachabilityInternal         (SCDynamicStoreRef              *storeP,
+                                                SCNetworkReachabilityFlags     *flags,
+                                                Boolean                        *haveDNS,
+                                                const char                     *nodename,
+                                                const char                     *servname,
+                                                uint32_t                       *resolver_if_index,
+                                                int                            *dns_config_index);
+
+#endif // HAVE_REACHABILITY_SERVER
+
+__END_DECLS
+
+#endif // _SCNETWORKREACHABILITYINTERNAL_H
index efdc4b71cefa76209448f04c990ef34e122ac5a3..1d85e4348fd484fbf2dcdc4e96817872175438a5 100644 (file)
@@ -296,7 +296,7 @@ __SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef
 }
 
 
-__private_extern__ CFStringRef
+__private_extern__ CF_RETURNS_RETAINED CFStringRef
 __SCNetworkServiceNextName(SCNetworkServiceRef service)
 {
        CFArrayRef              components;
@@ -353,7 +353,7 @@ mergeDict(const void *key, const void *value, void *context)
 }
 
 
-static CFDictionaryRef
+static CF_RETURNS_RETAINED CFDictionaryRef
 _protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType)
 {
        SCNetworkInterfaceRef           interface;
@@ -1514,29 +1514,6 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name)
 #pragma mark SCNetworkService SPIs
 
 
-static Boolean
-str_to_rank(CFStringRef rankStr, SCNetworkServicePrimaryRank *rank)
-{
-       if (isA_CFString(rankStr)) {
-               if (CFEqual(rankStr, kSCValNetServicePrimaryRankFirst)) {
-                       *rank = kSCNetworkServicePrimaryRankFirst;
-               } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankLast)) {
-                       *rank = kSCNetworkServicePrimaryRankLast;
-               } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankNever)) {
-                       *rank = kSCNetworkServicePrimaryRankNever;
-               } else {
-                       return FALSE;
-               }
-       } else if (rankStr == NULL) {
-               *rank = kSCNetworkServicePrimaryRankDefault;
-       } else {
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-
 SCNetworkServicePrimaryRank
 SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
 {
@@ -1560,7 +1537,7 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
                CFRelease(path);
                if (isA_CFDictionary(entity)) {
                        rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
-                       ok = str_to_rank(rankStr, &rank);
+                       ok = __str_to_rank(rankStr, &rank);
                }
        } else if (servicePrivate->store != NULL) {
                path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
@@ -1572,7 +1549,7 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
                if (entity != NULL) {
                        if (isA_CFDictionary(entity)) {
                                rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
-                               ok = str_to_rank(rankStr, &rank);
+                               ok = __str_to_rank(rankStr, &rank);
                        }
                        CFRelease(entity);
                }
@@ -1592,30 +1569,6 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
 }
 
 
-static Boolean
-rank_to_str(SCNetworkServicePrimaryRank rank, CFStringRef *rankStr)
-{
-       switch (rank) {
-               case kSCNetworkServicePrimaryRankDefault :
-                       *rankStr = NULL;
-                       break;
-               case kSCNetworkServicePrimaryRankFirst :
-                       *rankStr = kSCValNetServicePrimaryRankFirst;
-                       break;
-               case kSCNetworkServicePrimaryRankLast :
-                       *rankStr = kSCValNetServicePrimaryRankLast;
-                       break;
-               case kSCNetworkServicePrimaryRankNever :
-                       *rankStr = kSCValNetServicePrimaryRankNever;
-                       break;
-               default :
-                       return FALSE;
-       }
-
-       return TRUE;
-}
-
-
 Boolean
 SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef             service,
                               SCNetworkServicePrimaryRank      newRank)
@@ -1632,7 +1585,7 @@ SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef                service,
                return FALSE;
        }
 
-       ok = rank_to_str(newRank, &rankStr);
+       ok = __rank_to_str(newRank, &rankStr);
        if (!ok) {
                _SCErrorSet(kSCStatusInvalidArgument);
                return FALSE;
index dad99e74b61f44279cfed2a1b14f0283657ada72..126300fe820bea67e1ac3a1ee4f036a62b85dda8 100644 (file)
@@ -1138,12 +1138,14 @@ copyExcludedInterfaces(SCPreferencesRef prefs)
 
        excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
 
+#if    !TARGET_OS_IPHONE
        // exclude Bond [member] interfaces
        interfaces = SCBondInterfaceCopyAll(prefs);
        if (interfaces != NULL) {
                __SCBondInterfaceListCollectMembers(interfaces, excluded);
                CFRelease(interfaces);
        }
+#endif // !TARGET_OS_IPHONE
 
        // exclude Bridge [member] interfaces
        interfaces = SCBridgeInterfaceCopyAll(prefs);
index d0296ae8397e1d80daca3d7bb863ac1b6a8a65a2..2be8e9b079744504aa75ad033dcbd8454103ed71 100644 (file)
 
 const char * kSCNetworkSignatureActiveChangedNotifyName = NETWORK_ID_KEY ".active";
 
+#pragma mark SCNetworkSignature Supporting APIs
 
-#pragma mark SCNetworkSignature support routines
+static CFStringRef
+create_global_state_v4_key(void)
+{
+       return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 
+                                                         kSCDynamicStoreDomainState,
+                                                         kSCEntNetIPv4);
+       
+}
+
+static CFStringRef
+create_global_setup_v4_key(void)
+{
+       return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
+                                                         kSCDynamicStoreDomainSetup,
+                                                         kSCEntNetIPv4);
+}
 
-static __inline__ SCDynamicStoreRef
-store_create(CFAllocatorRef alloc)
+static CFStringRef
+create_ipv4_services_pattern(void)
 {
-       return (SCDynamicStoreCreate(alloc, CFSTR("SCNetworkSignature"),
-                                    NULL, NULL));
+       return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                          kSCDynamicStoreDomainState,
+                                                          kSCCompAnyRegex,
+                                                          kSCEntNetIPv4);
+}
+
+static CFStringRef
+create_ipv6_services_pattern(void)
+{
+       return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                          kSCDynamicStoreDomainState,
+                                                          kSCCompAnyRegex,
+                                                          kSCEntNetIPv6);
 }
 
 static CFDictionaryRef
-store_copy_id_dict(CFAllocatorRef alloc, SCDynamicStoreRef store)
+copy_services_for_address_family(CFAllocatorRef alloc,
+                                 int af)
 {
-       CFDictionaryRef id_dict = NULL;
-       Boolean         release_store = FALSE;
+        CFDictionaryRef info;
+        CFArrayRef      patterns;
+        CFStringRef     pattern;
+        CFStringRef     prop;
+       
+        prop = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6;
+        pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                              kSCDynamicStoreDomainState,
+                                                              kSCCompAnyRegex,
+                                                              prop);
+        patterns = CFArrayCreate(NULL,
+                                 (const void * *)&pattern, 1,
+                                 &kCFTypeArrayCallBacks);
+        CFRelease(pattern);
+        info = SCDynamicStoreCopyMultiple(NULL, NULL, patterns);
+        CFRelease(patterns);
+       
+        return (info);
+}
 
-       if (store == NULL) {
-               store = store_create(alloc);
-               if (store == NULL) {
-                       goto done;
-               }
-               release_store = TRUE;
-       }
-       id_dict = SCDynamicStoreCopyValue(store,
-                                         kSCNetworkIdentificationStoreKey);
-       if (isA_CFDictionary(id_dict) == NULL) {
-               if (id_dict != NULL) {
-                       CFRelease(id_dict);
-                       id_dict = NULL;
-               }
-               goto done;
-       }
- done:
-       if (release_store) {
-               CFRelease(store);
+
+static CF_RETURNS_RETAINED CFStringRef
+my_IPAddressToCFString(int af, const void * src_p)
+{
+       char            ntopbuf[INET6_ADDRSTRLEN];
+       
+       if (inet_ntop(af, src_p, ntopbuf, sizeof(ntopbuf)) != NULL) {
+               return (CFStringCreateWithCString(NULL, ntopbuf,
+                                                 kCFStringEncodingASCII));
        }
-       return (id_dict);
+       return (NULL);
 }
 
-#pragma -
+#pragma mark -
+
 
 #pragma mark SCNetworkSignature APIs
 
@@ -96,35 +132,100 @@ CFStringRef
 SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc,
                                                 const struct sockaddr * addr)
 {
-       CFDictionaryRef         id_dict = NULL;
-       CFStringRef             ident = NULL;
+       CFStringRef             ident   = NULL;
+       CFDictionaryRef         info = NULL;
+       CFStringRef             global_state_v4_key = NULL;
+       CFDictionaryRef         global_v4_state_dict = NULL;
+       CFArrayRef              keys = NULL;
+       CFArrayRef              patterns = NULL;
+       in_addr_t               s_addr; 
+       CFStringRef             service = NULL;
+       CFDictionaryRef         service_dict = NULL;
+       CFStringRef             service_id = NULL;
        struct sockaddr_in *    sin_p;
-
+       CFStringRef             v4_service_pattern = NULL;
 
        /* only accept 0.0.0.0 (i.e. default) for now */
-       sin_p = (struct sockaddr_in *)addr;
        if (addr == NULL
            || addr->sa_family != AF_INET
-           || addr->sa_len != sizeof(struct sockaddr_in)
-           || sin_p->sin_addr.s_addr != 0) {
+           || addr->sa_len != sizeof(struct sockaddr_in)){
                _SCErrorSet(kSCStatusInvalidArgument);
                goto done;
        }
-       id_dict = store_copy_id_dict(alloc, NULL);
-       if (id_dict == NULL) {
-               _SCErrorSet(kSCStatusFailed);
+
+       /* ALIGN: force alignment */
+       sin_p = (struct sockaddr_in *)(void *)addr;
+       bcopy(&sin_p->sin_addr.s_addr, &s_addr, sizeof(s_addr));
+       if (s_addr != 0) {
+               _SCErrorSet(kSCStatusInvalidArgument);
                goto done;
        }
-       ident = CFDictionaryGetValue(id_dict, kStoreKeyPrimaryIPv4Identifier);
-       if (isA_CFString(ident) != NULL) {
-               CFRetain(ident);
+       
+       global_state_v4_key = create_global_state_v4_key();
+       keys = CFArrayCreate(NULL, (const void * *)&global_state_v4_key, 
+                            1, &kCFTypeArrayCallBacks);
+       
+       v4_service_pattern = create_ipv4_services_pattern();
+       patterns = CFArrayCreate(NULL,  (const void * *)&v4_service_pattern, 1,
+                                &kCFTypeArrayCallBacks);
+
+       info = SCDynamicStoreCopyMultiple(NULL, keys, patterns);
+       
+       if (info == NULL 
+           || CFDictionaryGetCount(info) == 0) {
+               goto done;
        }
-       else {
+
+       global_v4_state_dict = CFDictionaryGetValue(info, global_state_v4_key);
+
+       if (isA_CFDictionary(global_v4_state_dict) == NULL) {
+               goto done;
+       }
+       
+       service_id = CFDictionaryGetValue(global_v4_state_dict,
+                                          kSCDynamicStorePropNetPrimaryService);
+
+       if (isA_CFString(service_id) == NULL) {
+               goto done;
+       }
+       
+       service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                             kSCDynamicStoreDomainState,
+                                                             service_id, kSCEntNetIPv4);
+       
+       service_dict = CFDictionaryGetValue(info, service);
+
+       
+       if (isA_CFDictionary(service_dict) == NULL 
+           || CFDictionaryGetCount(service_dict) == 0) {
+               goto done;
+       }
+
+       ident = CFDictionaryGetValue(service_dict, kStoreKeyNetworkSignature);
+       ident = isA_CFString(ident);
+done:
+       if (ident != NULL) {
+               CFRetain(ident);
+       } else {
                _SCErrorSet(kSCStatusFailed);
        }
- done:
-       if (id_dict != NULL) {
-               CFRelease(id_dict);
+       if (info != NULL) {
+               CFRelease(info);
+       }
+       if (global_state_v4_key != NULL) {
+               CFRelease(global_state_v4_key);
+       }
+       if (service != NULL) {
+               CFRelease(service);
+       }
+       if (keys != NULL) {
+               CFRelease(keys);
+       }
+       if (patterns != NULL) {
+               CFRelease(patterns);
+       }
+       if (v4_service_pattern != NULL) {
+               CFRelease(v4_service_pattern);
        }
        return (ident);
 }
@@ -132,36 +233,157 @@ SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc,
 CFArrayRef /* of CFStringRef's */
 SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc)
 {
-       CFArrayRef              active = NULL;
-       int                     i;
+       CFMutableArrayRef       active = NULL;
        int                     count = 0;
-       CFDictionaryRef         id_dict = NULL;
+       CFStringRef             global_setup_v4_key = NULL;
+       CFDictionaryRef         global_v4_dict;
+       int                     i;
+       CFDictionaryRef         info = NULL;
+       CFArrayRef              keys = NULL;
+       CFMutableArrayRef       patterns = NULL;
+       CFRange                 range;
+       CFMutableDictionaryRef  services_dict = NULL;
+       CFArrayRef              service_order;
+       CFStringRef             v4_service_pattern = NULL;
+       CFStringRef             v6_service_pattern = NULL;
+       const void * *          values = NULL;
+#define KEYS_STATIC_COUNT      10
+       const void *            values_static[KEYS_STATIC_COUNT];
 
-       id_dict = store_copy_id_dict(alloc, NULL);
-       if (id_dict == NULL) {
+       patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+       global_setup_v4_key = create_global_setup_v4_key();
+       keys = CFArrayCreate(NULL, (const void * *)&global_setup_v4_key, 1,
+                            &kCFTypeArrayCallBacks);
+       
+       v4_service_pattern = create_ipv4_services_pattern();
+       CFArrayAppendValue(patterns, v4_service_pattern);
+       
+       v6_service_pattern = create_ipv6_services_pattern();
+       CFArrayAppendValue(patterns, v6_service_pattern);
+       
+       info = SCDynamicStoreCopyMultiple(NULL, keys, patterns);
+       
+       if (info == NULL 
+           || CFDictionaryGetCount(info) == 0) {
                goto done;
        }
-       active = CFDictionaryGetValue(id_dict, kStoreKeyActiveIdentifiers);
-       if (isA_CFArray(active) != NULL) {
-               count = CFArrayGetCount(active);
+
+       services_dict = CFDictionaryCreateMutableCopy(NULL, 0, info);
+       /*
+        * The service_dict should only contain services and once each
+        * service has been visited, it will be removed from the dictionary.    
+        */
+       CFDictionaryRemoveValue(services_dict, global_setup_v4_key);
+
+       global_v4_dict = CFDictionaryGetValue(info, global_setup_v4_key);
+
+       if (isA_CFDictionary(global_v4_dict) == NULL) {
+               service_order = CFDictionaryGetValue(global_v4_dict, 
+                                                    kSCPropNetServiceOrder);
+               if (isA_CFArray(service_order) != NULL) {
+                       count = CFArrayGetCount(service_order);
+               }
        }
-       if (count == 0) {
-               active = NULL;
-               goto done;
+       
+       active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       
+       range = CFRangeMake(0, 0);
+
+       for (i = 0; i < count ; i++) {
+               int                     j;
+               CFStringRef             network_sig;
+               CFStringRef             service;
+               CFStringRef             service_id; 
+               CFDictionaryRef         service_info;
+               CFStringRef             afs[2] = {kSCEntNetIPv4, kSCEntNetIPv6};
+               
+               service_id = CFArrayGetValueAtIndex(service_order, i);
+
+               if (isA_CFString(service_id) == NULL) {
+                       continue;
+               }
+
+               for (j = 0; j < 2; j++) {
+                       service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                               kSCDynamicStoreDomainState,
+                                               service_id, afs[j]);
+               
+                       service_info = CFDictionaryGetValue(services_dict, service);
+
+                       /* Does this service have a signature? */
+                       if (isA_CFDictionary(service_info) != NULL) {
+                               network_sig = CFDictionaryGetValue(service_info, kStoreKeyNetworkSignature);
+                               if (isA_CFString(network_sig) != NULL
+                                   && CFArrayContainsValue(active, range, network_sig) == FALSE) {
+                                       CFArrayAppendValue(active, network_sig);
+                                       network_sig = NULL;
+                                       range.length++;
+                               }
+                               CFDictionaryRemoveValue(services_dict, service);
+                       }
+                       CFRelease(service);
+               }
        }
-       for (i = 0; i < count; i++) {
-               CFStringRef     ident = CFArrayGetValueAtIndex(active, i);
 
-               if (isA_CFString(ident) == NULL) {
-                       active = NULL;
-                       goto done;
+       count = CFDictionaryGetCount(services_dict);
+
+       if (count != 0) {
+               if (count > KEYS_STATIC_COUNT) {
+                       values = (const void * *)malloc(sizeof(*values) * count);
+               } else {
+                       values = values_static;
                }
+               CFDictionaryGetKeysAndValues(services_dict, NULL,
+                                            (const void * *)values);
        }
-       CFRetain(active);
+       
+       for (i = 0; i < count; i++) {
+               CFStringRef             network_sig;
+               CFDictionaryRef         service_dict = (CFDictionaryRef)values[i];
 
+               if (isA_CFDictionary(service_dict) == NULL) {
+                       continue;
+               }
+
+               network_sig = CFDictionaryGetValue(service_dict,
+                                                  kStoreKeyNetworkSignature);
+               /* Does this service have a signature? */
+               if (isA_CFString(network_sig) != NULL 
+                   && CFArrayContainsValue(active, range, network_sig) == FALSE) {
+                       CFArrayAppendValue(active, network_sig);
+                       range.length++;
+                       network_sig = NULL;
+               }
+       }               
  done:
-       if (id_dict != NULL) {
-               CFRelease(id_dict);
+       if (info != NULL) {
+               CFRelease(info);
+       }
+       if (services_dict != NULL) {
+               CFRelease(services_dict);
+       }
+       if (global_setup_v4_key != NULL) {
+               CFRelease(global_setup_v4_key);
+       }
+       if (v4_service_pattern != NULL) {
+               CFRelease(v4_service_pattern);
+       }
+       if (v6_service_pattern != NULL) {
+               CFRelease(v6_service_pattern);
+       }
+       if (values != NULL && values != values_static) {
+               free(values);
+       }
+       if (keys != NULL) {
+               CFRelease(keys);
+       }
+       if (patterns != NULL) {
+               CFRelease(patterns);
+       }
+       if (active != NULL && CFArrayGetCount(active) == 0) {
+               CFRelease(active);
+               active = NULL;
        }
        if (active == NULL) {
                _SCErrorSet(kSCStatusFailed);
@@ -169,51 +391,6 @@ SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc)
        return (active);
 }
 
-static CFDictionaryRef
-copy_services_for_address_family(CFAllocatorRef alloc,
-                                SCDynamicStoreRef store, int af)
-{
-       CFDictionaryRef info;
-       CFArrayRef      patterns;
-       CFStringRef     pattern;
-       CFStringRef     prop;
-       Boolean         release_store = FALSE;
-
-       if (store == NULL) {
-               store = store_create(alloc);
-               if (store == NULL) {
-                       return (NULL);
-               }
-               release_store = TRUE;
-       }
-       prop = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6;
-       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
-                                                             kSCDynamicStoreDomainState,
-                                                             kSCCompAnyRegex,
-                                                             prop);
-       patterns = CFArrayCreate(NULL,
-                                (const void * *)&pattern, 1,
-                                &kCFTypeArrayCallBacks);
-       CFRelease(pattern);
-       info = SCDynamicStoreCopyMultiple(store, NULL, patterns);
-       CFRelease(patterns);
-       if (release_store) {
-               CFRelease(store);
-       }
-       return (info);
-}
-
-static CFStringRef
-my_IPAddressToCFString(int af, const void * src_p)
-{
-       char            ntopbuf[INET6_ADDRSTRLEN];
-
-       if (inet_ntop(af, src_p, ntopbuf, sizeof(ntopbuf)) != NULL) {
-               return (CFStringCreateWithCString(NULL, ntopbuf,
-                                                 kCFStringEncodingASCII));
-       }
-       return (NULL);
-}
 
 CFStringRef
 SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc,
@@ -226,7 +403,7 @@ SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc,
        const void * *          keys = NULL;
 #define KEYS_STATIC_COUNT      10
        const void *            keys_static[KEYS_STATIC_COUNT];
-       static const void *     local_ip_p;
+       const void *            local_ip_p;
        CFStringRef             local_ip_str = NULL;
        CFStringRef             ret_signature = NULL;
        CFDictionaryRef         service_info = NULL;
@@ -258,7 +435,7 @@ SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc,
        }
 
        /* find a service matching the local IP and get its network signature */
-       service_info = copy_services_for_address_family(alloc, NULL, af);
+       service_info = copy_services_for_address_family(alloc, af);
        if (service_info == NULL) {
                goto done;
        }
index 41bd0d7f96026e82c37769736700650571dcc8dc..10926a62979904f7b8e717c81a3a4a6e44c5adc1 100644 (file)
 #define _SCNETWORKSIGNATURE_H
 
 #include <Availability.h>
+#include <sys/cdefs.h>
 #include <CoreFoundation/CFString.h>
 #include <CoreFoundation/CFArray.h>
 #include <netinet/in.h>
 
+__BEGIN_DECLS
+
 /*!
        @header SCNetworkSignature
        @discussion The SCNetworkSignature API provides access to the
@@ -98,4 +101,7 @@ SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc,
 CFStringRef
 SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc,
                                                   int sock_fd) __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/);
+
+__END_DECLS
+
 #endif /* _SCNETWORKSIGNATURE_H */
index fc79654406f418bdd373334f2e1655a453ffaa74..344b4200e48699e0813e19339cdac07e36ae2f02 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2005, 2007-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2007-2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -41,7 +41,7 @@
 #include <sys/errno.h>
 #include <sys/param.h>
 
-__private_extern__ CFDataRef
+__private_extern__ CF_RETURNS_RETAINED CFDataRef
 __SCPSignatureFromStatbuf(const struct stat *statBuf)
 {
        CFMutableDataRef        signature;
@@ -49,7 +49,10 @@ __SCPSignatureFromStatbuf(const struct stat *statBuf)
 
        signature = CFDataCreateMutable(NULL, sizeof(SCPSignatureData));
        CFDataSetLength(signature, sizeof(SCPSignatureData));
-       sig = (SCPSignatureDataRef)CFDataGetBytePtr(signature);
+
+       /* ALIGN: CFDataGetBytePtr aligns to at least 8 bytes */
+       sig = (SCPSignatureDataRef)(void *)CFDataGetBytePtr(signature);
+
        sig->st_dev       = statBuf->st_dev;
        sig->st_ino       = statBuf->st_ino;
        sig->tv_sec       = statBuf->st_mtimespec.tv_sec;
@@ -126,7 +129,7 @@ SCPreferencesGetSignature(SCPreferencesRef prefs)
 }
 
 
-__private_extern__ CFStringRef
+__private_extern__ CF_RETURNS_RETAINED CFStringRef
 _SCPNotificationKey(CFAllocatorRef     allocator,
                    CFStringRef         prefsID,
                    int                 keyType)
index b6fa4541ac66e4b004c749d30d92f55943e3aae5..7558a9ed5f36dbbdbe0d6917767aab0d7b2f121c 100644 (file)
 #include "dy_framework.h"
 
 #include <fcntl.h>
-#include <libproc.h>
 #include <pthread.h>
 #include <unistd.h>
 #include <sys/errno.h>
 
 
+const AuthorizationRef kSCPreferencesUseEntitlementAuthorization       = (AuthorizationRef)CFSTR("UseEntitlement");
+
+
 static __inline__ CFTypeRef
 isA_SCPreferences(CFTypeRef obj)
 {
@@ -218,7 +220,6 @@ __SCPreferencesCreate_helper(SCPreferencesRef prefs)
 {
        CFDataRef               data            = NULL;
        CFMutableDictionaryRef  info;
-       char                    name[64]        = "???";
        CFNumberRef             num;
        Boolean                 ok;
        SCPreferencesPrivateRef prefsPrivate    = (SCPreferencesPrivateRef)prefs;
@@ -258,8 +259,7 @@ __SCPreferencesCreate_helper(SCPreferencesRef prefs)
        CFRelease(num);
 
        // save process name
-       (void) proc_name(getpid(), name, sizeof(name));
-       str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+       str = CFStringCreateWithCString(NULL, getprogname(), kCFStringEncodingUTF8);
        CFDictionarySetValue(info, CFSTR("PROC_NAME"), str);
        CFRelease(str);
 
@@ -542,7 +542,7 @@ __SCPreferencesAccess(SCPreferencesRef      prefs)
 
        if (statBuf.st_size > 0) {
                CFDictionaryRef         dict;
-               CFErrorRef              error;
+               CFErrorRef              error   = NULL;
                CFMutableDataRef        xmlData;
 
                /*
@@ -631,9 +631,13 @@ SCPreferencesCreateWithAuthorization(CFAllocatorRef        allocator,
 {
        SCPreferencesRef        prefs;
 
-#if    TARGET_OS_IPHONE
-       authorization = (AuthorizationRef)1;
-#endif // TARGET_OS_IPHONE
+#if    !TARGET_OS_IPHONE
+       if (authorization == NULL) {
+               authorization = kSCPreferencesUseEntitlementAuthorization;
+       }
+#else  // !TARGET_OS_IPHONE
+       authorization = kSCPreferencesUseEntitlementAuthorization;
+#endif // !TARGET_OS_IPHONE
 
        prefs = SCPreferencesCreateWithOptions(allocator, name, prefsID, authorization, NULL);
        return prefs;
@@ -658,21 +662,35 @@ SCPreferencesCreateWithOptions(CFAllocatorRef     allocator,
        }
 
        if (authorization != NULL) {
+               CFMutableDictionaryRef  authorizationDict;
+               CFBundleRef             bundle;
+               CFStringRef             bundleID        = NULL;
+
+               authorizationDict =  CFDictionaryCreateMutable(NULL,
+                                                              0,
+                                                              &kCFTypeDictionaryKeyCallBacks,
+                                                              &kCFTypeDictionaryValueCallBacks);
 #if    !TARGET_OS_IPHONE
-               AuthorizationExternalForm       extForm;
-               OSStatus                        os_status;
+               if (authorization != kSCPreferencesUseEntitlementAuthorization) {
+                       CFDataRef                       authorizationRefData;
+                       AuthorizationExternalForm       extForm;
+                       OSStatus                        os_status;
+
+                       os_status = AuthorizationMakeExternalForm(authorization, &extForm);
+                       if (os_status != errAuthorizationSuccess) {
+                               SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen AuthorizationMakeExternalForm() failed"));
+                               _SCErrorSet(kSCStatusInvalidArgument);
+                               CFRelease(authorizationDict);
+                               return NULL;
+                       }
 
-               os_status = AuthorizationMakeExternalForm(authorization, &extForm);
-               if (os_status != errAuthorizationSuccess) {
-                       SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen AuthorizationMakeExternalForm() failed"));
-                       _SCErrorSet(kSCStatusInvalidArgument);
-                       return NULL;
+                       authorizationRefData = CFDataCreate(NULL, (const UInt8 *)extForm.bytes, sizeof(extForm.bytes));
+                       CFDictionaryAddValue(authorizationDict,
+                                            kSCHelperAuthAuthorization,
+                                            authorizationRefData);
+                       CFRelease(authorizationRefData);
                }
-
-               authorizationData = CFDataCreate(NULL, (const UInt8 *)extForm.bytes, sizeof(extForm.bytes));
-#else  // !TARGET_OS_IPHONE
-               CFBundleRef     bundle;
-               CFStringRef     bundleID        = NULL;
+#endif
 
                /* get the application/executable/bundle name */
                bundle = CFBundleGetMainBundle();
@@ -700,10 +718,18 @@ SCPreferencesCreateWithOptions(CFAllocatorRef     allocator,
                if (bundleID == NULL) {
                        bundleID = CFStringCreateWithFormat(NULL, NULL, CFSTR("Unknown(%d)"), getpid());
                }
-
-               _SCSerializeString(bundleID, &authorizationData, NULL, NULL);
+               CFDictionaryAddValue(authorizationDict,
+                                    kSCHelperAuthCallerInfo,
+                                    bundleID);
                CFRelease(bundleID);
-#endif // !TARGET_OS_IPHONE
+
+               if (authorizationDict != NULL) {
+                       _SCSerialize((CFPropertyListRef)authorizationDict,
+                                    &authorizationData,
+                                    NULL,
+                                    NULL);
+                       CFRelease(authorizationDict);
+               }
        }
 
        prefsPrivate = __SCPreferencesCreate(allocator, name, prefsID, authorizationData, options);
index 07945535140d94294df7f430ab1a6deaf3eea25a..bd947421ddce669a634cc0773f17895b8a5769d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2006, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -38,7 +38,7 @@
 
 #define        MAXLINKS        8
 
-static CFMutableArrayRef
+static CF_RETURNS_RETAINED CFMutableArrayRef
 normalizePath(CFStringRef path)
 {
        CFMutableArrayRef       elements;
index 7d62507f0a565ec8287ffb0bdbf2ffeebcfdc4f4..aca0a16c5ea9cdefc75df21ad5a65b7a3593c618 100644 (file)
@@ -126,6 +126,7 @@ __SCPreferencesAccess                       (SCPreferencesRef       prefs);
 Boolean
 __SCPreferencesAddSession              (SCPreferencesRef       prefs);
 
+CF_RETURNS_RETAINED
 CFDataRef
 __SCPSignatureFromStatbuf              (const struct stat      *statBuf);
 
@@ -134,6 +135,7 @@ __SCPreferencesPath                 (CFAllocatorRef         allocator,
                                         CFStringRef            prefsID,
                                         Boolean                useNewPrefs);
 
+CF_RETURNS_RETAINED
 CFStringRef
 _SCPNotificationKey                    (CFAllocatorRef         allocator,
                                         CFStringRef            prefsID,
index 95f18f9b780f52294d2e05e22dfc2e85a6a7881d..2690e17174ec6fc17a08d2915a3b3338b5e0039c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005, 2007-2009, 2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2007-2009, 2011, 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -37,6 +37,8 @@
 
 #define kSCPreferencesOptionRemoveWhenEmpty    CFSTR("remove-when-empty")      // CFBooleanRef
 
+#define kSCPreferencesWriteAuthorizationRight  "system.services.systemconfiguration.network"
+
 /*!
        @enum SCPreferencesKeyType
        @discussion Used with the SCDynamicStoreKeyCreatePreferences() function
@@ -56,6 +58,19 @@ typedef      int32_t SCPreferencesKeyType;
 
 __BEGIN_DECLS
 
+/*!
+       @const kSCPreferencesUseEntitlementAuthorization
+       @discussion An authorization value that can be passed to
+               the SCPreferencesCreateWithAuthorization API (or
+               the SCPreferencesCreateWithOptions SPI) to indicate
+               that the entitlements of the current process should
+               be used for authorization purposes.
+
+               This value can ONLY be used with the SCPreferences
+               APIs.
+ */
+extern const AuthorizationRef  kSCPreferencesUseEntitlementAuthorization;
+
 /*!
        @function SCDynamicStoreKeyCreatePreferences
        @discussion Creates a key that can be used by the SCDynamicStoreSetNotificationKeys()
index 96d5a39054b5ea499557a7788bc62d3bbfa741bf..509c59e236a93fa0f7e39e337b65ebf2baecc47b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -30,6 +30,7 @@
 #include <asl.h>
 #include <sys/syslog.h>
 #include <mach/message.h>
+#include <sys/sysctl.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 
        @header SCPrivate
  */
 
+
+/* atomic operations */
+#define _SC_ATOMIC_CMPXCHG(p, o, n)    __sync_bool_compare_and_swap((p), (o), (n))
+#define _SC_ATOMIC_INC(p)              __sync_fetch_and_add((p), 1)            // return (n++);
+#define _SC_ATOMIC_DEC(p)              __sync_sub_and_fetch((p), 1)            // return (--n);
+#define _SC_ATOMIC_ZERO(p)             __sync_fetch_and_and((p), 0)            // old_n = n; n = 0; return(old_n);
+
+
 /* framework variables */
 extern int     _sc_debug;      /* non-zero if debugging enabled */
 extern int     _sc_verbose;    /* non-zero if verbose logging enabled */
@@ -119,14 +128,35 @@ extern int        _sc_log;        /* 0 if SC messages should be written to stdout/stderr,
  */
 #define kSCNetworkReachabilityOptionInterface                  CFSTR("interface")
 
-
 /*!
-       @constant kSCNetworkReachabilityOptionConnectionOnDemandByPass
+       @constant kSCNetworkReachabilityOptionConnectionOnDemandBypass
        @discussion A CFBoolean that indicates if we should bypass the VPNOnDemand
                checks for this target.
  */
-#define kSCNetworkReachabilityOptionConnectionOnDemandByPass   CFSTR("ConnectionOnDemandByPass")
+#define kSCNetworkReachabilityOptionConnectionOnDemandBypass   CFSTR("ConnectionOnDemandBypass")
 
+/*!
+       @constant kSCNetworkReachabilityOptionResolverBypass
+       @discussion A CFBoolean that indicates if we should bypass resolving any
+               node names.  Instead, the status of the DNS server configuration
+               associated with the name will be returned. */
+#define kSCNetworkReachabilityOptionResolverBypass             CFSTR("ResolverBypass")
+
+
+/*!
+       @constant kSCNetworkReachabilityOptionLongLivedQueryBypass
+       @discussion A CFBoolean that indicates if we should bypass usage of any
+               long-lived-queries (w/DNSServiceCreateConnection) when resolving
+               hostnames for this target.
+ */
+#define kSCNetworkReachabilityOptionLongLivedQueryBypass       CFSTR("LongLivedQueryBypass")
+
+/*!
+       @constant kSCNetworkReachabilityOptionServerBypass
+       @discussion A CFBoolean that indicates if we should bypass usage of the
+               SCNetworkReachability "server" for this target.
+ */
+#define kSCNetworkReachabilityOptionServerBypass               CFSTR("ServerBypass")
 
 /*!
        @group
@@ -251,6 +281,7 @@ Boolean             _SCUnserializeData              (CFDataRef              *data,
        @param dict The CFDictionary with CFPropertyList values.
        @result The serialized CFDictionary with CFData values
  */
+CF_RETURNS_RETAINED
 CFDictionaryRef        _SCSerializeMultiple            (CFDictionaryRef        dict);
 
 /*!
@@ -261,6 +292,7 @@ CFDictionaryRef     _SCSerializeMultiple            (CFDictionaryRef        dict);
        @param dict The CFDictionary with CFData values.
        @result The serialized CFDictionary with CFPropertyList values
  */
+CF_RETURNS_RETAINED
 CFDictionaryRef        _SCUnserializeMultiple          (CFDictionaryRef        dict);
 
 
@@ -299,12 +331,31 @@ void              _SC_sockaddr_to_string          (const struct sockaddr  *address,
                                                 size_t                 bufLen);
 
 
+/*!
+ *     @function _SC_string_to_sockaddr
+ *     @discussion Parses a string into a "struct sockaddr"
+ *     @param str The address string to parse
+ *     @param af Allowed address families (AF_UNSPEC, AF_INET, AF_INET6)
+ *     @param buf A user provided buffer of the specified length; NULL
+ *             if a new buffer should be allocated (and deallocated by the
+ *             caller).
+ *     @param bufLen The size of the user provided buffer.
+ *     @result A pointer to the parsed "struct sockaddr"; NULL if
+ *             the string could not be parsed as an IP[v6] address.
+ */
+struct sockaddr *
+_SC_string_to_sockaddr                         (const char             *str,
+                                                sa_family_t            af,
+                                                void                   *buf,
+                                                size_t                 bufLen);
+
 /*!
  *     @function _SC_trimDomain
  *     @discussion Trims leading and trailing "."s from a domain or host name
  *     @param domain The domain name to trim
  *     @result The trimmed domain name.
  */
+CF_RETURNS_RETAINED
 CFStringRef    _SC_trimDomain                  (CFStringRef            domain);
 
 
@@ -483,6 +534,33 @@ _SC_checkResolverReachabilityByAddress             (SCDynamicStoreRef              *storeP,
                                                 Boolean                        *haveDNS,
                                                 struct sockaddr                *sa);
 
+/*!
+       @function SCNetworkReachabilityGetInterfaceIndex
+       @discussion Returns the interface index associated with network interface that will
+               be used to interact with the target host.
+       @param target The SCNetworkReachability reference associated with the address or
+               name to be checked for reachability.
+       @result Returns the interface index associated with the target.  Returning -1 means that
+               the target is not reachable.
+ */
+int
+SCNetworkReachabilityGetInterfaceIndex         (SCNetworkReachabilityRef       target);
+
+#pragma mark -
+#pragma mark Domain
+
+/*!
+       @function    _SC_domainEndsWithDomain
+       @discussion  Checks if one domain is a subset of another
+       @param compare_domain The domain to be compared.
+       @param match_domain The domain to be matched.
+       @return TRUE if the match_domain is contained in the compare_domain.
+                FLASE otherwise.
+ */
+Boolean
+_SC_domainEndsWithDomain                       (CFStringRef                    compare_domain,
+                                                CFStringRef                    match_domain);
+
 #pragma mark -
 #pragma mark NetBIOS
 
@@ -589,6 +667,39 @@ _SC_isAppleInternal()
        return (isInternal == 1);
 }
 
+#define        MODEL                   CFSTR("Model")
+
+static __inline__ CFStringRef
+_SC_hw_model()
+{
+       /*
+        * S_model
+        *   Hardware model for this network configuration.
+        */
+       static CFStringRef              model                   = NULL;
+
+       if (model == NULL) {
+               char    hwModel[64];
+               int     mib[]           = { CTL_HW, HW_MODEL };
+               size_t  n               = sizeof(hwModel);
+               int     ret;
+
+               // get HW model name
+               bzero(&hwModel, sizeof(hwModel));
+               ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &hwModel, &n, NULL, 0);
+               if (ret != 0) {
+                       SCLog(TRUE, LOG_ERR, CFSTR("sysctl() CTL_HW/HW_MODEL failed: %s"), strerror(errno));
+                       return NULL;
+               }
+               hwModel[sizeof(hwModel) - 1] = '\0';
+
+               model = CFStringCreateWithCString(NULL, hwModel, kCFStringEncodingASCII);
+       }
+
+       return model;
+
+}
+
 /*
  * debugging
  */
index 68fa5e0e8eb1c64aae35866da87089a1296189fd..b041e3cc94da3005de289bd25e85c72890130fe4 100644 (file)
@@ -123,90 +123,73 @@ validate_proxy_content(CFMutableDictionaryRef     proxies,
 }
 
 
-CFDictionaryRef
-SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
-{
-       CFArrayRef              array;
-       CFStringRef             key;
-       CFMutableDictionaryRef  newProxies      = NULL;
-       CFNumberRef             num;
-       CFDictionaryRef         proxies;
-       Boolean                 tempSession     = FALSE;
+static void
+normalize_scoped_proxy(const void *key, const void *value, void *context);
 
 
-       /* copy proxy information from dynamic store */
-
-       if (store == NULL) {
-               store = SCDynamicStoreCreate(NULL,
-                                            CFSTR("SCDynamicStoreCopyProxies"),
-                                            NULL,
-                                            NULL);
-               if (store == NULL) {
-                       return NULL;
-               }
-               tempSession = TRUE;
-       }
-
-       key = SCDynamicStoreKeyCreateProxies(NULL);
-       proxies = SCDynamicStoreCopyValue(store, key);
-       CFRelease(key);
+static void
+normalize_supplemental_proxy(const void *value, void *context);
 
-    validate :
 
-       if (proxies != NULL) {
-               if (isA_CFDictionary(proxies)) {
-                       newProxies = CFDictionaryCreateMutableCopy(NULL, 0, proxies);
-               }
-               CFRelease(proxies);
-       }
-
-       if (newProxies == NULL) {
-               newProxies = CFDictionaryCreateMutable(NULL,
-                                                      0,
-                                                      &kCFTypeDictionaryKeyCallBacks,
-                                                      &kCFTypeDictionaryValueCallBacks);
+static CF_RETURNS_RETAINED CFDictionaryRef
+__SCNetworkProxiesCopyNormalized(CFDictionaryRef proxy)
+{
+       CFArrayRef              array;
+       CFMutableDictionaryRef  newProxy;
+       CFNumberRef             num;
+       CFDictionaryRef         scoped;
+       CFArrayRef              supplemental;
+
+       if (!isA_CFDictionary(proxy)) {
+               proxy = CFDictionaryCreate(NULL,
+                                          NULL,
+                                          NULL,
+                                          0,
+                                          &kCFTypeDictionaryKeyCallBacks,
+                                          &kCFTypeDictionaryValueCallBacks);
+               return proxy;
        }
 
-       /* validate [and augment] proxy content */
+       newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
 
-       validate_proxy_content(newProxies,
+       validate_proxy_content(newProxy,
                               kSCPropNetProxiesFTPEnable,
                               kSCPropNetProxiesFTPProxy,
                               kSCPropNetProxiesFTPPort,
                               "ftp",
                               21);
-       validate_proxy_content(newProxies,
+       validate_proxy_content(newProxy,
                               kSCPropNetProxiesGopherEnable,
                               kSCPropNetProxiesGopherProxy,
                               kSCPropNetProxiesGopherPort,
                               "gopher",
                               70);
-       validate_proxy_content(newProxies,
+       validate_proxy_content(newProxy,
                               kSCPropNetProxiesHTTPEnable,
                               kSCPropNetProxiesHTTPProxy,
                               kSCPropNetProxiesHTTPPort,
                               "http",
                               80);
-       validate_proxy_content(newProxies,
+       validate_proxy_content(newProxy,
                               kSCPropNetProxiesHTTPSEnable,
                               kSCPropNetProxiesHTTPSProxy,
                               kSCPropNetProxiesHTTPSPort,
                               "https",
                               443);
-       validate_proxy_content(newProxies,
+       validate_proxy_content(newProxy,
                               kSCPropNetProxiesRTSPEnable,
                               kSCPropNetProxiesRTSPProxy,
                               kSCPropNetProxiesRTSPPort,
                               "rtsp",
                               554);
-       validate_proxy_content(newProxies,
+       validate_proxy_content(newProxy,
                               kSCPropNetProxiesSOCKSEnable,
                               kSCPropNetProxiesSOCKSProxy,
                               kSCPropNetProxiesSOCKSPort,
                               "socks",
                               1080);
-       if (CFDictionaryContainsKey(newProxies, kSCPropNetProxiesProxyAutoConfigURLString)) {
-               validate_proxy_content(newProxies,
+       if (CFDictionaryContainsKey(newProxy, kSCPropNetProxiesProxyAutoConfigURLString)) {
+               validate_proxy_content(newProxy,
                                       kSCPropNetProxiesProxyAutoConfigEnable,
                                       kSCPropNetProxiesProxyAutoConfigURLString,
                                       NULL,
@@ -214,16 +197,16 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
                                       0);
 
                // and we can't have both URLString and JavaScript keys
-               CFDictionaryRemoveValue(newProxies, kSCPropNetProxiesProxyAutoConfigJavaScript);
+               CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesProxyAutoConfigJavaScript);
        } else {
-               validate_proxy_content(newProxies,
+               validate_proxy_content(newProxy,
                                       kSCPropNetProxiesProxyAutoConfigEnable,
                                       kSCPropNetProxiesProxyAutoConfigJavaScript,
                                       NULL,
                                       NULL,
                                       0);
        }
-       validate_proxy_content(newProxies,
+       validate_proxy_content(newProxy,
                               kSCPropNetProxiesProxyAutoDiscoveryEnable,
                               NULL,
                               NULL,
@@ -231,7 +214,7 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
                               0);
 
        // validate FTP passive setting
-       num = CFDictionaryGetValue(newProxies, kSCPropNetProxiesFTPPassive);
+       num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesFTPPassive);
        if (num != NULL) {
                int     enabled = 0;
 
@@ -240,7 +223,7 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
                        // if we don't like the enabled key/value
                        enabled = 1;
                        num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
-                       CFDictionarySetValue(newProxies,
+                       CFDictionarySetValue(newProxy,
                                             kSCPropNetProxiesFTPPassive,
                                             num);
                        CFRelease(num);
@@ -248,7 +231,7 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
        }
 
        // validate proxy exception list
-       array = CFDictionaryGetValue(newProxies, kSCPropNetProxiesExceptionsList);
+       array = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExceptionsList);
        if (array != NULL) {
                CFIndex         i;
                CFIndex         n;
@@ -266,12 +249,12 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
                }
 
                if (n == 0) {
-                       CFDictionaryRemoveValue(newProxies, kSCPropNetProxiesExceptionsList);
+                       CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesExceptionsList);
                }
        }
 
        // validate exclude simple hostnames setting
-       num = CFDictionaryGetValue(newProxies, kSCPropNetProxiesExcludeSimpleHostnames);
+       num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExcludeSimpleHostnames);
        if (num != NULL) {
                int     enabled;
 
@@ -280,18 +263,110 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
                        // if we don't like the enabled key/value
                        enabled = 0;
                        num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
-                       CFDictionarySetValue(newProxies,
+                       CFDictionarySetValue(newProxy,
                                             kSCPropNetProxiesExcludeSimpleHostnames,
                                             num);
                        CFRelease(num);
                }
        }
 
+       // cleanup scoped proxies
+       scoped = CFDictionaryGetValue(newProxy, kSCPropNetProxiesScoped);
+       if (isA_CFDictionary(scoped)) {
+               CFMutableDictionaryRef  newScoped;
+
+               newScoped = CFDictionaryCreateMutable(NULL,
+                                                     0,
+                                                     &kCFTypeDictionaryKeyCallBacks,
+                                                     &kCFTypeDictionaryValueCallBacks);
+               CFDictionaryApplyFunction(scoped,
+                                         normalize_scoped_proxy,
+                                         newScoped);
+               CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, newScoped);
+               CFRelease(newScoped);
+       }
+
+       // cleanup split/supplemental proxies
+       supplemental = CFDictionaryGetValue(newProxy, kSCPropNetProxiesSupplemental);
+       if (isA_CFArray(supplemental)) {
+               CFMutableArrayRef       newSupplemental;
+
+               newSupplemental = CFArrayCreateMutable(NULL,
+                                                      0,
+                                                      &kCFTypeArrayCallBacks);
+               CFArrayApplyFunction(supplemental,
+                                    CFRangeMake(0, CFArrayGetCount(supplemental)),
+                                    normalize_supplemental_proxy,
+                                    newSupplemental);
+               CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, newSupplemental);
+               CFRelease(newSupplemental);
+       }
+
+       proxy = CFDictionaryCreateCopy(NULL,newProxy);
+       CFRelease(newProxy);
+
+       return proxy;
+}
+
+
+static void
+normalize_scoped_proxy(const void *key, const void *value, void *context)
+{
+       CFStringRef             interface       = (CFStringRef)key;
+       CFDictionaryRef         proxy           = (CFDictionaryRef)value;
+       CFMutableDictionaryRef  newScoped       = (CFMutableDictionaryRef)context;
+
+       proxy = __SCNetworkProxiesCopyNormalized(proxy);
+       CFDictionarySetValue(newScoped, interface, proxy);
+       CFRelease(proxy);
+
+       return;
+}
+
+
+static void
+normalize_supplemental_proxy(const void *value, void *context)
+{
+       CFDictionaryRef         proxy           = (CFDictionaryRef)value;
+       CFMutableArrayRef       newSupplemental = (CFMutableArrayRef)context;
+
+       proxy = __SCNetworkProxiesCopyNormalized(proxy);
+       CFArrayAppendValue(newSupplemental, proxy);
+       CFRelease(proxy);
+
+       return;
+}
+
+
+CFDictionaryRef
+SCDynamicStoreCopyProxies(SCDynamicStoreRef store)
+{
+       CFStringRef             key;
+       CFDictionaryRef         proxies;
+
+
+       /* copy proxy information from dynamic store */
+
+       key = SCDynamicStoreKeyCreateProxies(NULL);
+       proxies = SCDynamicStoreCopyValue(store, key);
+       CFRelease(key);
+
+
+       if (proxies != NULL) {
+               CFDictionaryRef base    = proxies;
+
+               proxies = __SCNetworkProxiesCopyNormalized(base);
+               CFRelease(base);
+       } else {
+               proxies = CFDictionaryCreate(NULL,
+                                            NULL,
+                                            NULL,
+                                            0,
+                                            &kCFTypeDictionaryKeyCallBacks,
+                                            &kCFTypeDictionaryValueCallBacks);
+       }
 
-       proxies = CFDictionaryCreateCopy(NULL, newProxies);
-       CFRelease(newProxies);
 
-       if (tempSession)        CFRelease(store);
        return proxies;
 }
 
@@ -356,7 +431,7 @@ SCNetworkProxiesCopyMatching(CFDictionaryRef        globalConfiguration,
        if (server != NULL) {
                CFIndex                 i;
                CFMutableArrayRef       matching        = NULL;
-               CFIndex                 n;
+               CFIndex                 n               = 0;
                CFIndex                 server_len;
                CFArrayRef              supplemental;
 
@@ -370,18 +445,16 @@ SCNetworkProxiesCopyMatching(CFDictionaryRef      globalConfiguration,
                server_len = CFStringGetLength(server);
 
                supplemental = CFDictionaryGetValue(globalConfiguration, kSCPropNetProxiesSupplemental);
-               if (supplemental == NULL) {
-                       // if no supplemental configurations
-                       goto done;
-               }
+               if (supplemental != NULL) {
+                       if (!isA_CFArray(supplemental)) {
+                               // if corrupt proxy configuration
+                               sc_status = kSCStatusFailed;
+                               goto done;
+                       }
 
-               if (!isA_CFArray(supplemental)) {
-                       // if corrupt proxy configuration
-                       sc_status = kSCStatusFailed;
-                       goto done;
+                       n = CFArrayGetCount(supplemental);
                }
 
-               n = CFArrayGetCount(supplemental);
                for (i = 0; i < n; i++) {
                        CFStringRef     domain;
                        CFIndex         domain_len;
index 159a37d2d5b8d7a968c12a5fb8a0f22ad90798d2..583307d9f9028110ec5a3ff96ad859ffd3b65e15 100644 (file)
@@ -62,6 +62,7 @@ const CFStringRef kSCEntNet6to4                                    = CFSTR("6to4
 
 
 const CFStringRef kSCEntNetEAPOL                                   = CFSTR("EAPOL");
+const CFStringRef kSCEntNetLinkQuality                             = CFSTR("LinkQuality");
 const CFStringRef kSCEntNetLoopback                                = CFSTR("Loopback");
 const CFStringRef kSCEntNetOnDemand                                = CFSTR("OnDemand");
 const CFStringRef kSCEntNetService                                 = CFSTR("__SERVICE__");
@@ -187,6 +188,8 @@ const CFStringRef kSCValNetIPv4ConfigMethodFailover                = CFSTR("Fail
 const CFStringRef kSCPropNetIPv4RouteDestinationAddress            = CFSTR("DestinationAddress");
 const CFStringRef kSCPropNetIPv4RouteSubnetMask                    = CFSTR("SubnetMask");
 const CFStringRef kSCPropNetIPv4RouteGatewayAddress                = CFSTR("GatewayAddress");
+const CFStringRef kSCPropNetIPv4ARPResolvedHardwareAddress         = CFSTR("ARPResolvedHardwareAddress");
+const CFStringRef kSCPropNetIPv4ARPResolvedIPAddress               = CFSTR("ARPResolvedIPAddress");
 const CFStringRef kSCPropNetIPv6Addresses                          = CFSTR("Addresses");
 const CFStringRef kSCPropNetIPv6ConfigMethod                       = CFSTR("ConfigMethod");
 const CFStringRef kSCPropNetIPv6DestAddresses                      = CFSTR("DestAddresses");
@@ -206,6 +209,7 @@ const CFStringRef kSCPropNetIPv6RouteGatewayAddress                = CFSTR("Gate
 const CFStringRef kSCPropNet6to4Relay                              = CFSTR("Relay");
 const CFStringRef kSCPropNetLinkActive                             = CFSTR("Active");
 const CFStringRef kSCPropNetLinkDetaching                          = CFSTR("Detaching");
+const CFStringRef kSCPropNetLinkQuality                            = CFSTR("LinkQuality");
 const CFStringRef kSCPropNetModemAccessPointName                   = CFSTR("AccessPointName");
 const CFStringRef kSCPropNetModemConnectionPersonality             = CFSTR("ConnectionPersonality");
 const CFStringRef kSCPropNetModemConnectionScript                  = CFSTR("ConnectionScript");
index f7cebc1fb2430871d3dd00bb05d22e6fe8210d64..ee3ca283b59f6c06d51b52b3950b3baeb665f7eb 100644 (file)
@@ -35,6 +35,7 @@
  *
  *   kSCEntNetCommCenter                                "com.apple.CommCenter"         CFDictionary
  *   kSCEntNetEAPOL                                     "EAPOL"                        CFDictionary
+ *   kSCEntNetLinkQuality                               "LinkQuality"                  CFDictionary
  *   kSCEntNetLoopback                                  "Loopback"                     CFDictionary
  *   kSCEntNetOnDemand                                  "OnDemand"                     CFDictionary
  *   kSCEntNetService                                   "__SERVICE__"                  CFDictionary
@@ -91,6 +92,9 @@
  *   kSCPropNetIPv4RouteSubnetMask                      "SubnetMask"                   CFString
  *   kSCPropNetIPv4RouteGatewayAddress                  "GatewayAddress"               CFString
  *
+ *   kSCPropNetIPv4ARPResolvedHardwareAddress           "ARPResolvedHardwareAddress"   CFString
+ *   kSCPropNetIPv4ARPResolvedIPAddress                 "ARPResolvedIPAddress"         CFString
+ *
  * kSCEntNetIPv6 Entity Keys
  *
  *   kSCPropNetIPv6ExcludedRoutes                       "ExcludedRoutes"               CFArray[CFDictionary]
  *   kSCPropNetIPv6RoutePrefixLength                    "PrefixLength"                 CFNumber
  *   kSCPropNetIPv6RouteGatewayAddress                  "GatewayAddress"               CFString
  *
+ * kSCEntNetLinkQuality Entity Keys
+ *
+ *   kSCPropNetLinkQuality                              "LinkQuality"                  CFNumber
+ *
  * kSCEntNetPPP Entity Keys
  *
  *   --- OnDemand: ---
@@ -234,6 +242,12 @@ extern const CFStringRef kSCEntNetCommCenter;
  */
 extern const CFStringRef kSCEntNetEAPOL;
 
+/*!
+  @const kSCEntNetLinkQuality
+  @availability Introduced in Mac OS X 10.7.
+ */
+extern const CFStringRef kSCEntNetLinkQuality;
+
 /*!
   @const kSCEntNetLoopback
   @availability Introduced in Mac OS X 10.7.
@@ -438,6 +452,18 @@ extern const CFStringRef kSCPropNetIPv4RouteSubnetMask;
  */
 extern const CFStringRef kSCPropNetIPv4RouteGatewayAddress;
 
+/*!
+  @const kSCPropNetIPv4ARPResolvedHardwareAddress
+  @availability Introduced in Mac OS X 10.7.
+ */
+extern const CFStringRef kSCPropNetIPv4ARPResolvedHardwareAddress;
+
+/*!
+  @const kSCPropNetIPv4ARPResolvedIPAddress
+  @availability Introduced in Mac OS X 10.7.
+ */
+extern const CFStringRef kSCPropNetIPv4ARPResolvedIPAddress;
+
 /*!
   @group kSCEntNetIPv6 Entity Keys
  */
@@ -472,6 +498,16 @@ extern const CFStringRef kSCPropNetIPv6RoutePrefixLength;
  */
 extern const CFStringRef kSCPropNetIPv6RouteGatewayAddress;
 
+/*!
+  @group kSCEntNetLinkQuality Entity Keys
+ */
+
+/*!
+  @const kSCPropNetLinkQuality
+  @availability Introduced in Mac OS X 10.7.
+ */
+extern const CFStringRef kSCPropNetLinkQuality;
+
 /*!
   @group kSCEntNetPPP Entity Keys
  */
@@ -863,6 +899,12 @@ extern const CFStringRef kSCPropVirtualNetworkInterfacesVLANOptions;
                      ,"EAPOL"                                          \
                      ,CFDictionary                                     )
 
+  SC_SCHEMA_DECLARATION(kSCEntNetLinkQuality, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/))
+  #define kSCEntNetLinkQuality                                          \
+         SC_SCHEMA_KV(kSCEntNetLinkQuality                             \
+                     ,"LinkQuality"                                    \
+                     ,CFDictionary                                     )
+
   SC_SCHEMA_DECLARATION(kSCEntNetLoopback, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0/*SPI*/))
   #define kSCEntNetLoopback                                             \
          SC_SCHEMA_KV(kSCEntNetLoopback                                \
@@ -1032,6 +1074,18 @@ extern const CFStringRef kSCPropVirtualNetworkInterfacesVLANOptions;
                      ,"GatewayAddress"                                 \
                      ,CFString                                         )
 
+  SC_SCHEMA_DECLARATION(kSCPropNetIPv4ARPResolvedHardwareAddress, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/))
+  #define kSCPropNetIPv4ARPResolvedHardwareAddress                      \
+         SC_SCHEMA_KV(kSCPropNetIPv4ARPResolvedHardwareAddress         \
+                     ,"ARPResolvedHardwareAddress"                     \
+                     ,CFString                                         )
+
+  SC_SCHEMA_DECLARATION(kSCPropNetIPv4ARPResolvedIPAddress, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/))
+  #define kSCPropNetIPv4ARPResolvedIPAddress                            \
+         SC_SCHEMA_KV(kSCPropNetIPv4ARPResolvedIPAddress               \
+                     ,"ARPResolvedIPAddress"                           \
+                     ,CFString                                         )
+
   SC_SCHEMA_DECLARATION(kSCPropNetIPv6ExcludedRoutes, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0/*SPI*/))
   #define kSCPropNetIPv6ExcludedRoutes                                  \
          SC_SCHEMA_KV(kSCPropNetIPv6ExcludedRoutes                     \
@@ -1062,6 +1116,12 @@ extern const CFStringRef kSCPropVirtualNetworkInterfacesVLANOptions;
                      ,"GatewayAddress"                                 \
                      ,CFString                                         )
 
+  SC_SCHEMA_DECLARATION(kSCPropNetLinkQuality, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/))
+  #define kSCPropNetLinkQuality                                         \
+         SC_SCHEMA_KV(kSCPropNetLinkQuality                            \
+                     ,"LinkQuality"                                    \
+                     ,CFNumber                                         )
+
   SC_SCHEMA_DECLARATION(kSCPropNetPPPOnDemandDomains, __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0/*SPI*/))
   #define kSCPropNetPPPOnDemandDomains                                  \
          SC_SCHEMA_KV(kSCPropNetPPPOnDemandDomains                     \
index 0323b945a15c088a7f62387fdb028096123be410..a73c9100e709f1fd99ed1cd23f58258e9a2efd55 100644 (file)
@@ -378,11 +378,13 @@ SCVLANInterfaceCopyAvailablePhysicalInterfaces()
 
        prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL);
        if (prefs != NULL) {
+#if    !TARGET_OS_IPHONE
                bond_interfaces = SCBondInterfaceCopyAll(prefs);
                if (bond_interfaces != NULL) {
                        excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
                        __SCBondInterfaceListCollectMembers(bond_interfaces, excluded);
                }
+#endif // !TARGET_OS_IPHONE
 
                bridge_interfaces = SCBridgeInterfaceCopyAll(prefs);
                if (bridge_interfaces != NULL) {
index 4b09c0a458fc91b2492d43c1be8536183d4827ac..a6665c3f1738b74bc8f6b1dd68ca04dcb37b6bcb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2011, 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -71,14 +71,9 @@ routine configopen   (       server          : mach_port_t;
                         out    status          : int;
            ServerAuditToken    audit_token     : audit_token_t);
 
-routine configclose    (       server          : mach_port_t;
-                        out    status          : int);
-
-routine configlock     (       server          : mach_port_t;
-                        out    status          : int);
-
-routine configunlock   (       server          : mach_port_t;
-                        out    status          : int);
+       skip;   /* was configclose */
+       skip;   /* was configlock */
+       skip;   /* was configunlock */
 
        skip;   /* reserved for future use */
        skip;   /* reserved for future use */
@@ -93,34 +88,37 @@ routine configlist  (       server          : mach_port_t;
                                xmlData         : xmlData;
                                isRegex         : int;
                         out    list            : xmlDataOut, dealloc;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
 
 routine configadd      (       server          : mach_port_t;
                                key             : xmlData;
                                data            : xmlData;
                         out    newInstance     : int;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
 
 routine configget      (       server          : mach_port_t;
                                key             : xmlData;
                         out    data            : xmlDataOut, dealloc;
                         out    newInstance     : int;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
 
 routine configset      (       server          : mach_port_t;
                                key             : xmlData;
                                data            : xmlData;
                                instance        : int;
                         out    newInstance     : int;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
 
 routine configremove   (       server          : mach_port_t;
                                key             : xmlData;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
 
-routine configtouch    (       server          : mach_port_t;
-                               key             : xmlData;
-                        out    status          : int);
+       skip;   /* was configtouch */
 
 routine configadd_s    (       server          : mach_port_t;
                                key             : xmlData;
@@ -130,19 +128,22 @@ routine configadd_s       (       server          : mach_port_t;
 
 routine confignotify   (       server          : mach_port_t;
                                key             : xmlData;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
 
 routine configget_m    (       server          : mach_port_t;
                                keys            : xmlData;
                                patterns        : xmlData;
                         out    data            : xmlDataOut, dealloc;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
 
 routine configset_m    (       server          : mach_port_t;
                                data            : xmlData;
                                remove          : xmlData;
                                notify          : xmlData;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
 
 /*
  * Notification API's
@@ -194,4 +195,5 @@ routine notifyset   (       server          : mach_port_t;
  */
 
 routine snapshot       (       server          : mach_port_t;
-                        out    status          : int);
+                        out    status          : int;
+           ServerAuditToken    audit_token     : audit_token_t);
index e69f9aba9781d18ca0290cbb68d635647e8e39eb..4cb153accaba9ec10ae32fdff2ccf3c516e6d2fc 100644 (file)
@@ -45,7 +45,7 @@ static void *
 __loadIOKit(void) {
        static void *image = NULL;
        if (NULL == image) {
-               const char      *framework              = "/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit";
+               const char      *framework              = "/System/Library/Frameworks/IOKit.framework/IOKit";
                struct stat     statbuf;
                const char      *suffix                 = getenv("DYLD_IMAGE_SUFFIX");
                char            path[MAXPATHLEN];
@@ -276,11 +276,7 @@ static void *
 __loadSecurity(void) {
        static void *image = NULL;
        if (NULL == image) {
-#if    TARGET_OS_IPHONE
                const char      *framework              = "/System/Library/Frameworks/Security.framework/Security";
-#else
-               const char      *framework              = "/System/Library/Frameworks/Security.framework/Versions/A/Security";
-#endif
                struct stat     statbuf;
                const char      *suffix                 = getenv("DYLD_IMAGE_SUFFIX");
                char            path[MAXPATHLEN];
@@ -296,8 +292,6 @@ __loadSecurity(void) {
        return (void *)image;
 }
 
-#if    !TARGET_OS_IPHONE
-
 #define        SECURITY_FRAMEWORK_EXTERN(t, s)                         \
        __private_extern__ t                                    \
        _ ## s()                                                \
@@ -310,6 +304,7 @@ __loadSecurity(void) {
                return (dysym != NULL) ? *dysym : NULL;         \
        }
 
+#if    !TARGET_OS_IPHONE
 SECURITY_FRAMEWORK_EXTERN(CFTypeRef, kSecAttrService)
 SECURITY_FRAMEWORK_EXTERN(CFTypeRef, kSecClass)
 SECURITY_FRAMEWORK_EXTERN(CFTypeRef, kSecClassGenericPassword)
@@ -513,7 +508,24 @@ _SecTrustedApplicationCreateFromPath(const char *path, SecTrustedApplicationRef
        return dyfunc ? dyfunc(path, app) : -1;
 }
 
-#endif // !TARGET_OS_IPHONE
+#else  // TARGET_OS_IPHONE
+
+SECURITY_FRAMEWORK_EXTERN(CFStringRef, kSecPropertyKeyValue)
+SECURITY_FRAMEWORK_EXTERN(CFStringRef, kSecPropertyKeyLabel)
+
+__private_extern__ CFArrayRef
+_SecCertificateCopyProperties(SecCertificateRef certRef)
+{
+       #undef SecCertificateCopyProperties
+       static typeof (SecCertificateCopyProperties) *dyfunc = NULL;
+       if (!dyfunc) {
+               void *image = __loadSecurity();
+               if (image) dyfunc = dlsym(image, "SecCertificateCopyProperties");
+       }
+       return dyfunc ? dyfunc(certRef) : NULL;
+}
+
+#endif // TARGET_OS_IPHONE
 
 __private_extern__ SecCertificateRef
 _SecCertificateCreateWithData(CFAllocatorRef allocator, CFDataRef data)
index 6a4359fdb6ccded67ebfcd4def7f595d3a3792c3..09d4f11a6adbb63cb19a51665506c5d6c6ed3918 100644 (file)
@@ -32,6 +32,7 @@
 #include <CoreFoundation/CoreFoundation.h>
 #include <IOKit/IOKitLib.h>
 #include <Security/Security.h>
+#include <Security/SecCertificatePriv.h>
 #include <Security/SecItem.h>  // only needed for Mac OS X 10.6[.x]
 
 __BEGIN_DECLS
@@ -144,7 +145,7 @@ _IORegistryEntrySearchCFProperty    (
                                        CFStringRef             key,
                                        CFAllocatorRef          allocator,
                                        IOOptionBits            options
-                                       );
+                                       ) CF_RETURNS_RETAINED;
 #define IORegistryEntrySearchCFProperty _IORegistryEntrySearchCFProperty
 
 kern_return_t
@@ -232,34 +233,34 @@ _SecItemCopyMatching                      (
 
 OSStatus
 _SecKeychainCopyDomainDefault          (
-                                       SecPreferencesDomain                    domain,
-                                       SecKeychainRef                          *keychain
+                                       SecPreferencesDomain            domain,
+                                       SecKeychainRef                  *keychain
                                        );
 #define SecKeychainCopyDomainDefault _SecKeychainCopyDomainDefault
 
 OSStatus
 _SecKeychainGetPreferenceDomain                (
-                                       SecPreferencesDomain                    *domain
+                                       SecPreferencesDomain            *domain
                                        );
 #define SecKeychainGetPreferenceDomain _SecKeychainGetPreferenceDomain
 
 OSStatus
 _SecKeychainOpen                       (
-                                       const char                              *pathName,
-                                       SecKeychainRef                          *keychain
+                                       const char                      *pathName,
+                                       SecKeychainRef                  *keychain
                                        );
 #define SecKeychainOpen _SecKeychainOpen
 
 OSStatus
 _SecKeychainSetDomainDefault           (
-                                       SecPreferencesDomain                    domain,
-                                       SecKeychainRef                          keychain
+                                       SecPreferencesDomain            domain,
+                                       SecKeychainRef                  keychain
                                        );
 #define SecKeychainSetDomainDefault _SecKeychainSetDomainDefault
 
 OSStatus
 _SecKeychainSetPreferenceDomain                (
-                                       SecPreferencesDomain                    domain
+                                       SecPreferencesDomain            domain
                                        );
 #define SecKeychainSetPreferenceDomain _SecKeychainSetPreferenceDomain
 
@@ -315,13 +316,27 @@ _SecTrustedApplicationCreateFromPath      (
                                        );
 #define SecTrustedApplicationCreateFromPath _SecTrustedApplicationCreateFromPath
 
-#endif // !TARGET_OS_IPHONE
+#else  // TARGET_OS_IPHONE
+
+CFStringRef _kSecPropertyKeyValue();
+#define kSecPropertyKeyValue _kSecPropertyKeyValue()
+
+CFStringRef _kSecPropertyKeyLabel();
+#define kSecPropertyKeyLabel _kSecPropertyKeyLabel()
+
+CFArrayRef
+_SecCertificateCopyProperties          (
+                                       SecCertificateRef               certRef
+                                       );
+#define SecCertificateCopyProperties _SecCertificateCopyProperties
+
+#endif // TARGET_OS_IPHONE
 
 SecCertificateRef
-_SecCertificateCreateWithData(
-                             CFAllocatorRef allocator,
-                             CFDataRef data
-                             );
+_SecCertificateCreateWithData          (
+                                       CFAllocatorRef                  allocator,
+                                       CFDataRef                       data
+                                       );
 #define SecCertificateCreateWithData _SecCertificateCreateWithData
 
 __END_DECLS
index ec98374c1936fcee28ad50cdda8791a9cbf0c707..5cff79768517a07f475a0f7cf14175a2807e8377 100644 (file)
@@ -146,6 +146,7 @@ typedef enum {
 #define CFNUMBER_BOOL          "CFNumber (0 or 1)"
 #define CFSTRING               "CFString"
 
+#define ARP                    "ARP"
 #define ACCESSPOINTNAME                "AccessPointName"
 #define ACSP                   "ACSP"                  // Apple Client Server Protocol
 #define ACTIVE                 "Active"
@@ -274,6 +275,7 @@ typedef enum {
 #define LCP                    "LCP"
 #define LINK                   "Link"
 #define LINKLOCAL              "LinkLocal"
+#define LINKQUALITY            "LinkQuality"
 #define LOCALCERTIFICATE       "LocalCertificate"
 #define LOCALHOSTNAME          "LocalHostName"
 #define LOCALIDENTIFIER                "LocalIdentifier"
@@ -348,6 +350,7 @@ typedef enum {
 #define REMINDER               "Reminder"
 #define REMINDERTIME           "ReminderTime"
 #define REMOTEADDRESS          "RemoteAddress"
+#define RESOLVED               "Resolved"
 #define RETRYCONNECTTIME       "RetryConnectTime"
 #define ROOTSEPARATOR          "RootSeparator"
 #define ROUTE                  "Route"
@@ -503,6 +506,7 @@ static schemaDefinition names[] = {
   { GROUP_PRIVATE, NETENT, "Network Entity Keys", NULL, NULL },
 
     { SC_10_5_PRIVATE, NETENT, EAPOL, NULL, CFDICTIONARY },
+    { SC_10_7_IPHONE_5_0_PRIVATE, NETENT, LINKQUALITY, NULL, CFDICTIONARY}, 
     { SC_10_7_IPHONE_4_0_PRIVATE, NETENT, LOOPBACK, NULL, CFDICTIONARY },
     { SC_10_6_IPHONE_3_0_PRIVATE, NETENT, ONDEMAND, NULL, CFDICTIONARY },
     { SC_10_6_IPHONE_2_0_PRIVATE, NETENT, SERVICE, "__SERVICE__", CFDICTIONARY },
@@ -718,6 +722,9 @@ static schemaDefinition names[] = {
     { SC_10_7_IPHONE_4_0_PRIVATE, NETPROP IPV4 ROUTE, SUBNETMASK, NULL, CFSTRING },
     { SC_10_7_IPHONE_4_0_PRIVATE, NETPROP IPV4 ROUTE, GATEWAY ADDRESS, NULL, CFSTRING },
     { COMMENT_PRIVATE, "", NULL, NULL, NULL },
+    { SC_10_7_IPHONE_5_0_PRIVATE, NETPROP IPV4, ARP RESOLVED HARDWARE ADDRESS, NULL, CFSTRING },
+    { SC_10_7_IPHONE_5_0_PRIVATE, NETPROP IPV4, ARP RESOLVED IP ADDRESS, NULL, CFSTRING },
+    { COMMENT_PRIVATE, "", NULL, NULL, NULL },
 
   { GROUP, NETPROP IPV6, KEY_PREFIX NETENT IPV6 " Entity Keys", NULL, NULL },
 
@@ -758,6 +765,11 @@ static schemaDefinition names[] = {
     { SC_10_2, NETPROP LINK, DETACHING, NULL, CFBOOLEAN },
     { COMMENT, "", NULL, NULL, NULL },
 
+  { GROUP_PRIVATE, NETPROP LINK, KEY_PREFIX NETENT LINKQUALITY " Entity Keys", NULL, NULL },
+
+    { SC_10_7_IPHONE_5_0_PRIVATE, NETPROP, LINKQUALITY, NULL, CFNUMBER},
+    { COMMENT_PRIVATE, "", NULL, NULL, NULL },
+
   { GROUP, NETPROP MODEM, KEY_PREFIX NETENT MODEM " (Hardware) Entity Keys", NULL, NULL },
 
     { SC_10_5, NETPROP MODEM, ACCESSPOINTNAME, NULL, CFSTRING },
index 7c69a2fcd985c2ce6f0583f6f5dedec90ec41143..1dc443cb98bde5a2bd78b4662fe4fd909b3c083b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2007, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -37,6 +37,7 @@
 #include <mach/mach_error.h>
 #include <servers/bootstrap.h>
 #include <bootstrap_priv.h>
+#include <pthread.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <SystemConfiguration/SCPrivate.h>
@@ -208,6 +209,33 @@ _SCHelperClose(mach_port_t *helper_port)
 }
 
 
+static CFDataRef
+_SCHelperExecCopyBacktrace()
+{
+       static Boolean          loggingEnabled  = FALSE;
+       static dispatch_once_t  once;
+       CFDataRef               traceData       = NULL;
+
+       dispatch_once(&once, ^{
+               if(getenv("ENABLE_SCHELPER_BACKTRACES")) {
+                       loggingEnabled = TRUE;
+               }
+       });
+
+       if (loggingEnabled) {
+               CFStringRef     backtrace;
+
+               backtrace = _SC_copyBacktrace();
+               if (backtrace != NULL) {
+                       _SCSerializeString(backtrace, &traceData, NULL, NULL);
+                       CFRelease(backtrace);
+               }
+       }
+
+       return traceData;
+}
+
+
 Boolean
 _SCHelperExec(mach_port_t port, uint32_t msgID, CFDataRef data, uint32_t *status, CFDataRef *reply)
 {
@@ -216,14 +244,24 @@ _SCHelperExec(mach_port_t port, uint32_t msgID, CFDataRef data, uint32_t *status
        xmlDataOut_t            replyRef        = NULL;         /* raw bytes */
        mach_msg_type_number_t  replyLen        = 0;
        uint32_t                replyStatus     = 0;
+       CFDataRef               traceData;
+
+       traceData = _SCHelperExecCopyBacktrace();
 
        kr = helperexec(port,
                        msgID,
                        (data != NULL) ? (void *)CFDataGetBytePtr(data) : NULL,
-                       (data != NULL) ? CFDataGetLength(data)  : 0,
+                       (data != NULL) ? CFDataGetLength(data) : 0,
+                       (traceData != NULL) ? (void *)CFDataGetBytePtr(traceData) : NULL,
+                       (traceData != NULL) ? CFDataGetLength(traceData) : 0,
                        &replyStatus,
                        &replyRef,
                        &replyLen);
+
+       if (traceData != NULL) {
+               CFRelease(traceData);
+       }
+
        if (kr != KERN_SUCCESS) {
                if (replyRef != NULL) {
                        (void) vm_deallocate(mach_task_self(), (vm_address_t)replyRef, replyLen);
index 02ecf7576f10d27b2a867f0049a67509897cba13..0db8a119f61b776dbd5939a5773efc3df2b7b47f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2007, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -35,6 +35,9 @@
 #define kSCKeychainOptionsPassword             CFSTR("Password")               // CFData
 #define kSCKeychainOptionsUniqueID             CFSTR("UniqueID")               // CFString
 
+#define kSCHelperAuthAuthorization             CFSTR("Authorization")          // CFData[AuthorizationExternalForm]
+#define kSCHelperAuthCallerInfo                        CFSTR("CallerInfo")             // CFString
+
 enum {
        // authorization
        SCHELPER_MSG_AUTH               = 1,
index 62957bdd5374744f3a519330975480b23b598452..ad83e9cfdebd39691e4f8b3994d3221d65bbb743 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -35,6 +35,8 @@
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <CoreFoundation/CFRuntime.h>
+#include <Security/Security.h>
+#include <Security/SecTask.h>
 #include <SystemConfiguration/SystemConfiguration.h>
 #include <SystemConfiguration/SCPrivate.h>
 #include <SystemConfiguration/SCValidation.h>
@@ -48,8 +50,6 @@
 #pragma mark SCHelper session managment
 
 
-#if    TARGET_OS_IPHONE
-
 //
 // entitlement used to control write access to a given "prefsID"
 //
@@ -60,9 +60,6 @@
 //
 #define kSCVPNFilterEntitlementName    CFSTR("com.apple.networking.vpn.configuration")
 
-#endif // TARGET_OS_IPHONE
-
-
 typedef        enum { NO = 0, YES, UNKNOWN } lazyBoolean;
 
 typedef const struct __SCHelperSession * SCHelperSessionRef;
@@ -77,6 +74,7 @@ typedef struct {
 
        // authorization
        AuthorizationRef        authorization;
+       Boolean                 use_entitlement;
 
        // session mach port
        mach_port_t             port;
@@ -94,6 +92,9 @@ typedef struct {
        // preferences
        SCPreferencesRef        prefs;
 
+       /* backtraces */
+       CFMutableSetRef         backtraces;
+
 } SCHelperSessionPrivate, *SCHelperSessionPrivateRef;
 
 
@@ -101,6 +102,9 @@ static CFStringRef  __SCHelperSessionCopyDescription        (CFTypeRef cf);
 static void            __SCHelperSessionDeallocate             (CFTypeRef cf);
 
 
+static void            __SCHelperSessionLogBacktrace           (const void *value, void *context);
+
+
 static CFTypeID                __kSCHelperSessionTypeID        = _kCFRuntimeNotATypeID;
 static Boolean         debug                           = FALSE;
 static pthread_once_t  initialized                     = PTHREAD_ONCE_INIT;
@@ -112,6 +116,18 @@ static pthread_mutex_t     sessions_lock                   = PTHREAD_MUTEX_INITIALIZER;
 
 
 #pragma mark -
+#pragma mark Helper session management
+
+
+#if !TARGET_OS_IPHONE
+static Boolean
+ __SCHelperSessionUseEntitlement(SCHelperSessionRef session)
+{
+       SCHelperSessionPrivateRef       sessionPrivate  = (SCHelperSessionPrivateRef)session;
+
+       return sessionPrivate->use_entitlement;
+}
+#endif //!TARGET_OS_IPHONE
 
 
 static AuthorizationRef
@@ -131,13 +147,23 @@ __SCHelperSessionSetAuthorization(SCHelperSessionRef session, CFTypeRef authoriz
 
        pthread_mutex_lock(&sessionPrivate->lock);
 
-#if    !TARGET_OS_IPHONE
        if (sessionPrivate->authorization != NULL) {
-               AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDefaults);
-//             AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDestroyRights);
-               sessionPrivate->authorization = NULL;
+#if !TARGET_OS_IPHONE
+               if (!__SCHelperSessionUseEntitlement(session)) {
+                       AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDefaults);
+//                     AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDestroyRights);
+                       sessionPrivate->authorization = NULL;
+               } else {
+#endif //!TARGET_OS_IPHONE
+                       CFRelease(sessionPrivate->authorization);
+                       sessionPrivate->authorization = NULL;
+#if !TARGET_OS_IPHONE
+               }
+#endif //!TARGET_OS_IPHONE
+               sessionPrivate->use_entitlement = FALSE;
        }
 
+#if !TARGET_OS_IPHONE
        if (isA_CFData(authorizationData)) {
                AuthorizationExternalForm       extForm;
 
@@ -155,17 +181,13 @@ __SCHelperSessionSetAuthorization(SCHelperSessionRef session, CFTypeRef authoriz
                                ok = FALSE;
                        }
                }
-       }
-#else  // !TARGET_OS_IPHONE
-       if (sessionPrivate->authorization != NULL) {
-               CFRelease(sessionPrivate->authorization);
-               sessionPrivate->authorization = NULL;
-       }
+       } else
+#endif //!TARGET_OS_IPHONE
 
        if (isA_CFString(authorizationData)) {
                sessionPrivate->authorization = (void *)CFRetain(authorizationData);
+               sessionPrivate->use_entitlement = TRUE;
        }
-#endif // !TARGET_OS_IPHONE
 
        pthread_mutex_unlock(&sessionPrivate->lock);
 
@@ -300,6 +322,7 @@ __SCHelperSessionLog(const void *value, void *context)
 {
        SCHelperSessionRef              session         = (SCHelperSessionRef)value;
        SCHelperSessionPrivateRef       sessionPrivate  = (SCHelperSessionPrivateRef)session;
+       FILE                            **logFile       = (FILE **)context;
 
        pthread_mutex_lock(&sessionPrivate->lock);
 
@@ -313,6 +336,19 @@ __SCHelperSessionLog(const void *value, void *context)
                      prefsPrivate->name,
                      prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path,
                      prefsPrivate->locked ? ", locked" : "");
+
+               if ((sessionPrivate->backtraces != NULL) &&
+                   (CFSetGetCount(sessionPrivate->backtraces) > 0)) {
+                       // log/report all collected backtraces
+                       CFSetApplyFunction(sessionPrivate->backtraces,
+                                          __SCHelperSessionLogBacktrace,
+                                          (void *)logFile);
+
+                       // to ensure that we don't log the same backtraces multiple
+                       // times we remove any reported traces
+                       CFRelease(sessionPrivate->backtraces);
+                       sessionPrivate->backtraces = NULL;
+               }
        }
 
        pthread_mutex_unlock(&sessionPrivate->lock);
@@ -380,6 +416,9 @@ __SCHelperSessionDeallocate(CFTypeRef cf)
        __SCHelperSessionSetPreferences  (session, NULL);
        __SCHelperSessionSetVPNFilter    (session, NULL);
        pthread_mutex_destroy(&sessionPrivate->lock);
+       if (sessionPrivate->backtraces != NULL) {
+               CFRelease(sessionPrivate->backtraces);
+       }
 
        // we no longer need/want to track this session
        CFSetRemoveValue(sessions, sessionPrivate);
@@ -427,11 +466,13 @@ __SCHelperSessionCreate(CFAllocatorRef allocator)
                return NULL;
        }
        sessionPrivate->authorization           = NULL;
+       sessionPrivate->use_entitlement         = FALSE;
        sessionPrivate->port                    = MACH_PORT_NULL;
        sessionPrivate->mp                      = NULL;
        sessionPrivate->callerWriteAccess       = UNKNOWN;
        sessionPrivate->vpnFilter               = NULL;
        sessionPrivate->prefs                   = NULL;
+       sessionPrivate->backtraces              = NULL;
 
        // keep track this session
        pthread_mutex_lock(&sessions_lock);
@@ -486,6 +527,84 @@ __SCHelperSessionFindWithPort(mach_port_t port)
 }
 
 
+#pragma mark -
+#pragma mark Session backtrace logging
+
+
+static void
+__SCHelperSessionAddBacktrace(SCHelperSessionRef session, CFStringRef backtrace, const char * command)
+{
+       CFStringRef                     logEntry;
+       SCPreferencesRef                prefs;
+       SCPreferencesPrivateRef         prefsPrivate;
+       SCHelperSessionPrivateRef       sessionPrivate  = (SCHelperSessionPrivateRef)session;
+
+       prefs = __SCHelperSessionGetPreferences((SCHelperSessionRef)sessionPrivate);
+       if (prefs == NULL) {
+               // if no prefs
+               return;
+       }
+       prefsPrivate = (SCPreferencesPrivateRef)prefs;
+
+       logEntry = CFStringCreateWithFormat(NULL, NULL,
+                                           CFSTR("%@ [%s]: %s\n\n%@"),
+                                           prefsPrivate->name,
+                                           prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path,
+                                           command,
+                                           backtrace);
+
+       pthread_mutex_lock(&sessionPrivate->lock);
+
+       if (sessionPrivate->backtraces == NULL) {
+               sessionPrivate->backtraces = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+       }
+       CFSetSetValue(sessionPrivate->backtraces, logEntry);
+
+       pthread_mutex_unlock(&sessionPrivate->lock);
+
+       CFRelease(logEntry);
+       return;
+}
+
+
+static void
+__SCHelperSessionLogBacktrace(const void *value, void *context)
+{
+       CFSetRef        backtrace       = (CFSetRef)value;
+       FILE            **logFile       = (FILE **)context;
+
+       if (*logFile == NULL) {
+               char            path[PATH_MAX];
+               struct tm       tm_now;
+               struct timeval  tv_now;
+
+               (void)gettimeofday(&tv_now, NULL);
+               (void)localtime_r(&tv_now.tv_sec, &tm_now);
+
+               snprintf(path,
+                        sizeof(path),
+                        "/Library/Logs/CrashReporter/SCHelper-%4d-%02d-%02d-%02d%02d%02d.log",
+                        tm_now.tm_year + 1900,
+                        tm_now.tm_mon + 1,
+                        tm_now.tm_mday,
+                        tm_now.tm_hour,
+                        tm_now.tm_min,
+                        tm_now.tm_sec);
+
+               *logFile = fopen(path, "a");
+               if (*logFile == NULL) {
+                       // if log file could not be created
+                       return;
+               }
+
+               SCLog(TRUE, LOG_INFO, CFSTR("created backtrace log: %s"), path);
+       }
+
+       SCPrint(TRUE, *logFile, CFSTR("%@\n"), backtrace);
+       return;
+}
+
+
 #pragma mark -
 #pragma mark Helpers
 
@@ -506,37 +625,46 @@ do_Exit(SCHelperSessionRef session, void *info, CFDataRef data, uint32_t *status
 
 /*
  * AUTHORIZE
- *   (in)  data   = AuthorizationExternalForm
+ *   (in)  data   = authorizationDict (in 2 flavors)
+ *                 kSCHelperAuthAuthorization - use provided AuthorizationExternalForm
+ *                 kSCHelperAuthCallerInfo    - use entitlement
  *   (out) status = OSStatus
  *   (out) reply  = N/A
  */
 static Boolean
 do_Auth(SCHelperSessionRef session, void *info, CFDataRef data, uint32_t *status, CFDataRef *reply)
 {
-       Boolean ok;
+       CFDictionaryRef authorizationDict;
+#if !TARGET_OS_IPHONE
+       CFDataRef       authorizationData       = NULL;
+#endif
+       Boolean         ok                      = FALSE;
 
-#if    !TARGET_OS_IPHONE
-
-       ok = __SCHelperSessionSetAuthorization(session, data);
-
-#else  //!TARGET_OS_IPHONE
-
-       CFStringRef     authorizationInfo       = NULL;
-
-       if ((data != NULL) && !_SCUnserializeString(&authorizationInfo, data, NULL, 0)) {
+       if (_SCUnserialize((CFPropertyListRef*)&authorizationDict, data, NULL, 0) == FALSE) {
                return FALSE;
        }
 
-       if (!isA_CFString(authorizationInfo)) {
-               if (authorizationInfo != NULL) CFRelease(authorizationInfo);
+       if (isA_CFDictionary(authorizationDict) == FALSE) {
+               CFRelease(authorizationDict);
                return FALSE;
        }
 
-       ok = __SCHelperSessionSetAuthorization(session, authorizationInfo);
-       if (authorizationInfo != NULL) CFRelease(authorizationInfo);
+#if !TARGET_OS_IPHONE
+       authorizationData = CFDictionaryGetValue(authorizationDict, kSCHelperAuthAuthorization);
+       if (authorizationData != NULL && isA_CFData(authorizationData)) {
+               ok = __SCHelperSessionSetAuthorization(session, authorizationData);
+       } else
+#endif
+       {
+               CFStringRef authorizationInfo;
 
-#endif // !TARGET_OS_IPHONE
+               authorizationInfo = CFDictionaryGetValue(authorizationDict, kSCHelperAuthCallerInfo);
+               if (authorizationInfo != NULL && isA_CFString(authorizationInfo)) {
+                       ok = __SCHelperSessionSetAuthorization(session, authorizationInfo);
+               }
+       }
 
+       CFRelease(authorizationDict);
        *status = ok ? 0 : 1;
        return TRUE;
 }
@@ -749,25 +877,33 @@ do_interface_refresh(SCHelperSessionRef session, void *info, CFDataRef data, uin
        Boolean         ok      = FALSE;
 
        if ((data != NULL) && !_SCUnserializeString(&ifName, data, NULL, 0)) {
+               *status = kSCStatusInvalidArgument;
                SCLog(TRUE, LOG_ERR, CFSTR("interface name not valid"));
                return FALSE;
        }
 
-       if (ifName != NULL) {
-               if (isA_CFString(ifName)) {
-                       ok = _SCNetworkInterfaceForceConfigurationRefresh(ifName);
-                       if (!ok) {
-                               *status = SCError();
-                       }
-               }
-
-               CFRelease(ifName);
+       if (ifName == NULL) {
+               *status = kSCStatusInvalidArgument;
+               SCLog(TRUE, LOG_ERR, CFSTR("interface name not valid"));
+               return FALSE;
        }
 
-       if (!ok) {
+       if (isA_CFString(ifName)) {
+               ok = _SCNetworkInterfaceForceConfigurationRefresh(ifName);
+               if (!ok) {
+                       *status = SCError();
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("interface \"%@\" not refreshed: %s"),
+                             ifName,
+                             SCErrorString(*status));
+               }
+       } else {
+               *status = kSCStatusInvalidArgument;
                SCLog(TRUE, LOG_ERR, CFSTR("interface name not valid"));
        }
 
+       CFRelease(ifName);
+
        return ok;
 }
 
@@ -1211,11 +1347,6 @@ do_prefs_Synchronize(SCHelperSessionRef session, void *info, CFDataRef data, uin
 #pragma mark Process commands
 
 
-#if    TARGET_OS_IPHONE
-
-#include <Security/Security.h>
-#include <Security/SecTask.h>
-
 static CFStringRef
 sessionName(SCHelperSessionRef session)
 {
@@ -1273,52 +1404,50 @@ copyEntitlement(SCHelperSessionRef session, CFStringRef entitlement)
        return value;
 }
 
-#endif // TARGET_OS_IPHONE
-
-
-
 
 static Boolean
 hasAuthorization(SCHelperSessionRef session)
 {
-       AuthorizationRef        authorization   = __SCHelperSessionGetAuthorization(session);
+       AuthorizationRef                authorization   = __SCHelperSessionGetAuthorization(session);
+       SCHelperSessionPrivateRef       sessionPrivate  = (SCHelperSessionPrivateRef)session;
 
        if (authorization == NULL) {
                return FALSE;
        }
 
-#if    !TARGET_OS_IPHONE
-       AuthorizationFlags      flags;
-       AuthorizationItem       items[1];
-       AuthorizationRights     rights;
-       OSStatus                status;
-
-       items[0].name        = "system.preferences";
-       items[0].value       = NULL;
-       items[0].valueLength = 0;
-       items[0].flags       = 0;
-
-       rights.count = sizeof(items) / sizeof(items[0]);
-       rights.items = items;
-
-       flags = kAuthorizationFlagDefaults;
-       flags |= kAuthorizationFlagExtendRights;
-       flags |= kAuthorizationFlagInteractionAllowed;
-//     flags |= kAuthorizationFlagPartialRights;
-//     flags |= kAuthorizationFlagPreAuthorize;
-
-       status = AuthorizationCopyRights(authorization,
-                                        &rights,
-                                        kAuthorizationEmptyEnvironment,
-                                        flags,
-                                        NULL);
-       if (status != errAuthorizationSuccess) {
-               return FALSE;
-       }
+#if !TARGET_OS_IPHONE
+       if (!__SCHelperSessionUseEntitlement(session)) {
+               AuthorizationFlags      flags;
+               AuthorizationItem       items[1];
+               AuthorizationRights     rights;
+               OSStatus                status;
+
+               items[0].name        = kSCPreferencesWriteAuthorizationRight;
+               items[0].value       = NULL;
+               items[0].valueLength = 0;
+               items[0].flags       = 0;
+
+               rights.count = sizeof(items) / sizeof(items[0]);
+               rights.items = items;
+
+               flags = kAuthorizationFlagDefaults;
+               flags |= kAuthorizationFlagExtendRights;
+               flags |= kAuthorizationFlagInteractionAllowed;
+//             flags |= kAuthorizationFlagPartialRights;
+//             flags |= kAuthorizationFlagPreAuthorize;
+
+               status = AuthorizationCopyRights(authorization,
+                                                &rights,
+                                                kAuthorizationEmptyEnvironment,
+                                                flags,
+                                                NULL);
+               if (status != errAuthorizationSuccess) {
+                       return FALSE;
+               }
 
-       return TRUE;
-#else  // !TARGET_OS_IPHONE
-       SCHelperSessionPrivateRef       sessionPrivate  = (SCHelperSessionPrivateRef)session;
+               return TRUE;
+       }
+#endif // !TARGET_OS_IPHONE
 
        if (sessionPrivate->callerWriteAccess == UNKNOWN) {
                CFArrayRef              entitlement;
@@ -1393,7 +1522,6 @@ hasAuthorization(SCHelperSessionRef session)
        }
 
        return (sessionPrivate->callerWriteAccess == YES) ? TRUE : FALSE;
-#endif // TARGET_OS_IPHONE
 }
 
 
@@ -1799,13 +1927,16 @@ _helperexec(mach_port_t                 server,
            uint32_t                    msgID,
            xmlData_t                   dataRef,        /* raw XML bytes */
            mach_msg_type_number_t      dataLen,
+           xmlData_t                   traceRef,       /* raw XML bytes */
+           mach_msg_type_number_t      traceLen,
            uint32_t                    *status,
            xmlDataOut_t                *replyRef,      /* raw XML bytes */
            mach_msg_type_number_t      *replyLen)
 {
-       CFDataRef                       data    = NULL;
+       CFStringRef                     backtrace       = NULL;
+       CFDataRef                       data            = NULL;
        int                             i;
-       CFDataRef                       reply   = NULL;
+       CFDataRef                       reply           = NULL;
        SCHelperSessionRef              session;
 
        *status   = kSCStatusOK;
@@ -1815,10 +1946,19 @@ _helperexec(mach_port_t                 server,
        if ((dataRef != NULL) && (dataLen > 0)) {
                if (!_SCUnserializeData(&data, (void *)dataRef, dataLen)) {
                        *status = SCError();
-                       return KERN_SUCCESS;
                }
        }
 
+       if ((traceRef != NULL) && (traceLen > 0)) {
+               if (!_SCUnserializeString(&backtrace, NULL, (void *)traceRef, traceLen)) {
+                       *status = SCError();
+               }
+       }
+
+       if (*status != kSCStatusOK) {
+               goto done;
+       }
+
        session = __SCHelperSessionFindWithPort(server);
        if (session == NULL) {
                *status = kSCStatusFailed;      /* you must have an open session to play */
@@ -1847,6 +1987,9 @@ _helperexec(mach_port_t                   server,
        }
 
        if (*status == kSCStatusOK) {
+               if (backtrace != NULL) {
+                       __SCHelperSessionAddBacktrace(session, backtrace, helpers[i].commandName);
+               }
                (*helpers[i].func)(session, helpers[i].info, data, status, &reply);
        }
 
@@ -1861,7 +2004,10 @@ _helperexec(mach_port_t                  server,
 
                /* serialize the data */
                if (reply != NULL) {
-                       ok = _SCSerializeData(reply, (void **)replyRef, (CFIndex *)replyLen);
+                       CFIndex         len;
+
+                       ok = _SCSerializeData(reply, (void **)replyRef, &len);
+                       *replyLen = len;
                        CFRelease(reply);
                        reply = NULL;
                        if (!ok) {
@@ -1874,6 +2020,7 @@ _helperexec(mach_port_t                   server,
     done :
 
        if (data  != NULL) CFRelease(data);
+       if (backtrace != NULL) CFRelease(backtrace);
        if (reply != NULL) CFRelease(reply);
        return KERN_SUCCESS;
 }
@@ -1971,7 +2118,7 @@ main(int argc, char **argv)
        launch_data_t           l_reply;
        launch_data_type_t      l_type;
        int                     n_listeners     = 0;
-       extern int              optind;
+//     extern int              optind;
        int                     opt;
        int                     opti;
 
@@ -2058,9 +2205,15 @@ main(int argc, char **argv)
 
                if (!done && (idle >= (2 * 60 / 15))) {
                        if (gen_reported != gen_current) {
+                               FILE    *logFile        = NULL;
+
                                SCLog(TRUE, LOG_NOTICE, CFSTR("active (but IDLE) sessions"));
-                               CFSetApplyFunction(sessions, __SCHelperSessionLog, NULL);
+                               CFSetApplyFunction(sessions, __SCHelperSessionLog, (void *)&logFile);
                                gen_reported = gen_current;
+
+                               if (logFile != NULL) {
+                                       (void) fclose(logFile);
+                               }
                        }
                        idle = 0;
                }
index e7d0b77202742c7d15db7d4afbf32d6fc49101be..e2544180de933db7dccbb1ee168164371d1e622f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -61,5 +61,6 @@ routine helperinit    (       server          : mach_port_t;
 routine helperexec     (       server          : mach_port_t;
                                msgID           : uint32_t;
                                data            : xmlData;
+                               trace           : xmlData;
                         out    status          : uint32_t;
                         out    reply           : xmlDataOut, dealloc);
diff --git a/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_client.c b/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_client.c
new file mode 100644 (file)
index 0000000..09c0ea6
--- /dev/null
@@ -0,0 +1,1186 @@
+/*
+ * Copyright (c) 2011, 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <SystemConfiguration/SCPrivate.h>
+#include "SCNetworkReachabilityInternal.h"
+
+#ifdef HAVE_REACHABILITY_SERVER
+
+#include <xpc/xpc.h>
+#include <xpc/private.h>
+
+#include "rb.h"
+
+
+#pragma mark -
+#pragma mark Globals
+
+
+static const struct addrinfo   hints0  = {
+#ifdef  AI_PARALLEL
+       .ai_flags       = AI_PARALLEL | AI_ADDRCONFIG
+#else  // AI_PARALLEL
+       .ai_flags       = AI_ADDRCONFIG
+#endif  // AI_PARALLEL
+};
+
+
+static Boolean                 serverAvailable = TRUE;
+
+
+#pragma mark -
+#pragma mark Support functions
+
+
+static void
+log_xpc_object(const char *msg, xpc_object_t obj)
+{
+       char            *desc;
+
+       desc = xpc_copy_description(obj);
+       SCLog(TRUE, LOG_DEBUG, CFSTR("%s = %s"), msg, desc);
+       free(desc);
+}
+
+
+#pragma mark -
+#pragma mark Reachability [RBT] client support
+
+
+typedef struct {
+       struct rb_node                  rbn;
+       SCNetworkReachabilityRef        target;
+} reach_request_t;
+
+
+#define RBNODE_TO_REACH_REQUEST(node) \
+       ((reach_request_t *)((uintptr_t)node - offsetof(reach_request_t, rbn)))
+
+
+static int
+_rbt_compare_transaction_nodes(const struct rb_node *n1, const struct rb_node *n2)
+{
+       uint64_t        a = (uintptr_t)(RBNODE_TO_REACH_REQUEST(n1)->target);
+       uint64_t        b = (uintptr_t)(RBNODE_TO_REACH_REQUEST(n2)->target);
+
+       return (a - b);
+}
+
+
+static int
+_rbt_compare_transaction_key(const struct rb_node *n1, const void *key)
+{
+       uint64_t        a = (uintptr_t)(RBNODE_TO_REACH_REQUEST(n1)->target);
+       uint64_t        b = *(uint64_t *)key;
+
+       return (a - b);
+}
+
+
+static struct rb_tree *
+_reach_requests_rbt()
+{
+       static dispatch_once_t          once;
+       static const struct rb_tree_ops ops = {
+               .rbto_compare_nodes     = _rbt_compare_transaction_nodes,
+               .rbto_compare_key       = _rbt_compare_transaction_key,
+       };
+       static struct rb_tree           rbtree;
+
+       dispatch_once(&once, ^{
+               rb_tree_init(&rbtree, &ops);
+       });
+
+       return &rbtree;
+}
+
+
+static dispatch_queue_t
+_reach_requests_rbt_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create(REACH_SERVICE_NAME ".rbt", NULL);
+       });
+
+       return q;
+}
+
+
+static reach_request_t *
+_reach_request_create(SCNetworkReachabilityRef target)
+{
+       reach_request_t *request;
+
+       request = calloc(1, sizeof(*request));
+       request->target = CFRetain(target);
+
+       return request;
+}
+
+
+static void
+_reach_request_release(reach_request_t *request)
+{
+       SCNetworkReachabilityRef        target  = request->target;
+
+       CFRelease(target);
+       free(request);
+
+       return;
+}
+
+
+static void
+_reach_request_add(SCNetworkReachabilityRef target)
+{
+       uint64_t        target_id       = (uintptr_t)target;
+
+       dispatch_sync(_reach_requests_rbt_queue(), ^{
+               struct rb_node          *rbn;
+
+               rbn = rb_tree_find_node(_reach_requests_rbt(), &target_id);
+               if (rbn == NULL) {
+                       reach_request_t *request;
+
+                       request = _reach_request_create(target);
+                       if (request == NULL || !rb_tree_insert_node(_reach_requests_rbt(), &request->rbn)) {
+                               __builtin_trap();
+                       }
+               }
+       });
+
+       return;
+}
+
+
+static void
+_reach_request_remove(SCNetworkReachabilityRef target)
+{
+       uint64_t        target_id       = (uintptr_t)target;
+
+       dispatch_sync(_reach_requests_rbt_queue(), ^{           // FIXME ?? use dispatch_async?
+               struct rb_node          *rbn;
+               struct rb_tree          *rbtree = _reach_requests_rbt();
+
+               rbn = rb_tree_find_node(rbtree, &target_id);
+               if (rbn != NULL) {
+                       reach_request_t *request        = RBNODE_TO_REACH_REQUEST(rbn);
+
+                       rb_tree_remove_node(rbtree, rbn);
+                       _reach_request_release(request);
+               }
+       });
+}
+
+
+static SCNetworkReachabilityRef
+_reach_request_copy_target(uint64_t target_id)
+{
+       __block SCNetworkReachabilityRef        target  = NULL;
+
+       dispatch_sync(_reach_requests_rbt_queue(), ^{
+               struct rb_node  *rbn;
+
+               rbn = rb_tree_find_node(_reach_requests_rbt(), &target_id);
+               if (rbn != NULL) {
+                       // handle the [async] reply
+                       target = (SCNetworkReachabilityRef)(uintptr_t)target_id;
+                       CFRetain(target);
+               }
+       });
+
+       return target;
+}
+
+
+#pragma mark -
+#pragma mark Reachability [XPC] client support
+
+
+static void
+handle_reachability_status(SCNetworkReachabilityRef target, xpc_object_t dict)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       if (_sc_debug) {
+               SCLog(TRUE, LOG_INFO, CFSTR("%sgot [async] notification"),
+                     targetPrivate->log_prefix);
+//             log_xpc_object("  status", dict);
+       }
+
+       __SCNetworkReachabilityPerformNoLock(target);
+
+       return;
+}
+
+
+static void
+handle_async_notification(SCNetworkReachabilityRef target, xpc_object_t dict)
+{
+       int64_t                         op;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       op = xpc_dictionary_get_int64(dict, MESSAGE_NOTIFY);
+       switch (op) {
+               case MESSAGE_REACHABILITY_STATUS :
+                       handle_reachability_status(target, dict);
+                       break;
+               default :
+                       SCLog(TRUE, LOG_ERR, CFSTR("%sgot [async] unknown reply : %d"),
+                             targetPrivate->log_prefix,
+                             op);
+                       log_xpc_object("  reply", dict);
+                       break;
+       }
+
+       return;
+}
+
+
+static dispatch_queue_t
+_reach_xpc_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create(REACH_SERVICE_NAME ".xpc", NULL);
+       });
+
+       return q;
+}
+
+
+static void
+_reach_connection_reconnect(xpc_connection_t connection);
+
+
+static xpc_connection_t
+_reach_connection_create()
+{
+       xpc_connection_t                c;
+       const char                      *name;
+       dispatch_queue_t                q       = _reach_xpc_queue();
+
+       // create XPC connection
+       name = getenv("REACH_SERVER");
+       if ((name == NULL) || (issetugid() != 0)) {
+               name = REACH_SERVICE_NAME;
+       }
+
+       c = xpc_connection_create_mach_service(name,
+                                              q,
+                                              XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+
+       xpc_connection_set_event_handler(c, ^(xpc_object_t xobj) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(xobj);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       SCNetworkReachabilityRef        target;
+                       uint64_t                        target_id;
+
+                       target_id = xpc_dictionary_get_uint64(xobj, REACH_CLIENT_TARGET_ID);
+                       if (target_id == 0) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("reach client %p: async reply with no target [ID]"),
+                                     c);
+                               log_xpc_object("  reply", xobj);
+                               return;
+                       }
+
+                       target = _reach_request_copy_target(target_id);
+                       if (target == NULL) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("received unexpected target [ID] from SCNetworkReachability server"));
+                               log_xpc_object("  reply", xobj);
+                               return;
+                       }
+
+                       handle_async_notification(target, xobj);
+                       CFRelease(target);
+
+               } else if (type == XPC_TYPE_ERROR) {
+                       if (xobj == XPC_ERROR_CONNECTION_INVALID) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("SCNetworkReachability server not available"));
+                               serverAvailable = FALSE;
+                       } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) {
+                               SCLog(TRUE, LOG_DEBUG,
+                                     CFSTR("SCNetworkReachability server failure, reconnecting"));
+                               _reach_connection_reconnect(c);
+                       } else {
+                               const char      *desc;
+
+                               desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION);
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("reach client %p: Connection error: %s"),
+                                     c,
+                                     desc);
+                       }
+
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("reach client %p: unknown event type : %x"),
+                             c,
+                             type);
+               }
+       });
+       xpc_connection_resume(c);
+
+       return c;
+}
+
+
+static xpc_connection_t
+_reach_connection()
+{
+       static xpc_connection_t         c;
+       static dispatch_once_t          once;
+       static dispatch_queue_t         q;
+
+       if (!serverAvailable) {
+               // if SCNetworkReachabilty [XPC] server not available
+               return NULL;
+       }
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create(REACH_SERVICE_NAME ".connection", NULL);
+       });
+
+       dispatch_sync(q, ^{
+               if (c == NULL) {
+                       c = _reach_connection_create();
+               }
+       });
+
+       return c;
+}
+
+
+typedef void (^reach_server_reply_handler_t)(xpc_object_t reply);
+
+
+static void
+add_proc_name(xpc_object_t reqdict)
+{
+       static const char       *name   = NULL;
+       static dispatch_once_t  once;
+
+       // add the process name
+       dispatch_once(&once, ^{
+               name = getprogname();
+       });
+       xpc_dictionary_set_string(reqdict, REACH_CLIENT_PROC_NAME, name);
+
+       return;
+}
+
+
+static void
+_reach_server_target_reconnect(xpc_connection_t connection, SCNetworkReachabilityRef target);
+
+
+static Boolean
+_reach_server_target_add(xpc_connection_t connection, SCNetworkReachabilityRef target)
+{
+       Boolean                         ok              = FALSE;
+       xpc_object_t                    reply;
+       xpc_object_t                    reqdict;
+       Boolean                         retry           = FALSE;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       // create message
+       reqdict = xpc_dictionary_create(NULL, NULL, 0);
+
+       // set request
+       xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_CREATE);
+
+       // add reachability target info
+       if (targetPrivate->name != NULL) {
+               xpc_dictionary_set_string(reqdict,
+                                         REACH_TARGET_NAME,
+                                         targetPrivate->name);
+       }
+       if (targetPrivate->serv != NULL) {
+               xpc_dictionary_set_string(reqdict,
+                                         REACH_TARGET_SERV,
+                                         targetPrivate->serv);
+       }
+       if (targetPrivate->localAddress != NULL) {
+               xpc_dictionary_set_data(reqdict,
+                                       REACH_TARGET_LOCAL_ADDR,
+                                       targetPrivate->localAddress,
+                                       targetPrivate->localAddress->sa_len);
+       }
+       if (targetPrivate->remoteAddress != NULL) {
+               xpc_dictionary_set_data(reqdict,
+                                       REACH_TARGET_REMOTE_ADDR,
+                                       targetPrivate->remoteAddress,
+                                       targetPrivate->remoteAddress->sa_len);
+       }
+       if (bcmp(&targetPrivate->hints, &hints0, sizeof(struct addrinfo)) != 0) {
+               xpc_dictionary_set_data(reqdict,
+                                       REACH_TARGET_HINTS,
+                                       &targetPrivate->hints,
+                                       sizeof(targetPrivate->hints));
+       }
+       if (targetPrivate->if_index != 0) {
+               xpc_dictionary_set_int64(reqdict,
+                                        REACH_TARGET_IF_INDEX,
+                                        targetPrivate->if_index);
+               xpc_dictionary_set_string(reqdict,
+                                         REACH_TARGET_IF_NAME,
+                                         targetPrivate->if_name);
+       }
+       if (targetPrivate->onDemandBypass) {
+               xpc_dictionary_set_bool(reqdict,
+                                       REACH_TARGET_ONDEMAND_BYPASS,
+                                       TRUE);
+       }
+       if (targetPrivate->resolverBypass) {
+               xpc_dictionary_set_bool(reqdict,
+                                       REACH_TARGET_RESOLVER_BYPASS,
+                                       TRUE);
+       }
+
+
+       // add the target [ID]
+       xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target);
+
+       // add the process name (for debugging)
+       add_proc_name(reqdict);
+
+    retry :
+
+       // send request to the SCNetworkReachability server
+       reply = xpc_connection_send_message_with_reply_sync(connection, reqdict);
+       if (reply != NULL) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(reply);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       int64_t         status;
+
+                       status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY);
+                       ok = (status == REACH_REQUEST_REPLY_OK);
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("SCNetworkReachability server not available"));
+                       serverAvailable = FALSE;
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) {
+                       SCLog(TRUE, LOG_DEBUG,
+                             CFSTR("reach target %p: SCNetworkReachability server failure, retrying"),
+                             target);
+                       retry = TRUE;
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("reach target %p: _targetAdd with unexpected reply"),
+                             target);
+                       log_xpc_object("  reply", reply);
+               }
+
+               xpc_release(reply);
+       }
+
+       if (retry) {
+               retry = FALSE;
+               goto retry;
+       }
+
+       xpc_release(reqdict);
+       return ok;
+}
+
+
+static Boolean
+_reach_server_target_remove(xpc_connection_t connection, SCNetworkReachabilityRef target)
+{
+       Boolean                         ok              = FALSE;
+       xpc_object_t                    reply;
+       xpc_object_t                    reqdict;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       // create message
+       reqdict = xpc_dictionary_create(NULL, NULL, 0);
+
+       // set request
+       xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_REMOVE);
+
+       // add the target [ID]
+       xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target);
+
+       reply = xpc_connection_send_message_with_reply_sync(connection, reqdict);
+       if (reply != NULL) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(reply);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       int64_t         status;
+
+                       status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY);
+                       switch (status) {
+                               case REACH_REQUEST_REPLY_OK :
+                                       ok = TRUE;
+                                       break;
+                               case REACH_REQUEST_REPLY_UNKNOWN :
+                                       SCLog(TRUE, LOG_DEBUG,
+                                             CFSTR("reach target %p: SCNetworkReachability server failure, no need to remove"),
+                                             target);
+                                       ok = TRUE;
+                                       break;
+                               default : {
+                                       SCLog(TRUE, LOG_ERR, CFSTR("%s  target remove failed"),
+                                             targetPrivate->log_prefix);
+                                       log_xpc_object("  reply", reply);
+                               }
+                       }
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("SCNetworkReachability server not available"));
+                       serverAvailable = FALSE;
+                       ok = TRUE;
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) {
+                       SCLog(TRUE, LOG_DEBUG,
+                             CFSTR("reach target %p: SCNetworkReachability server failure, no need to remove"),
+                             target);
+                       ok = TRUE;
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("reach target %p: _targetRemove with unexpected reply"),
+                             target);
+                       log_xpc_object("  reply", reply);
+               }
+
+               xpc_release(reply);
+       }
+
+       xpc_release(reqdict);
+       return ok;
+}
+
+
+static Boolean
+_reach_server_target_schedule(xpc_connection_t connection, SCNetworkReachabilityRef target)
+{
+       Boolean                         ok              = FALSE;
+       xpc_object_t                    reply;
+       xpc_object_t                    reqdict;
+       Boolean                         retry           = FALSE;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       // create message
+       reqdict = xpc_dictionary_create(NULL, NULL, 0);
+
+       // set request
+       xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_SCHEDULE);
+
+       // add the target [ID]
+       xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target);
+
+    retry :
+
+       reply = xpc_connection_send_message_with_reply_sync(connection, reqdict);
+       if (reply != NULL) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(reply);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       int64_t         status;
+
+                       status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY);
+                       switch (status) {
+                               case REACH_REQUEST_REPLY_OK :
+                                       ok = TRUE;
+                                       break;
+                               case REACH_REQUEST_REPLY_UNKNOWN :
+                                       SCLog(TRUE, LOG_DEBUG,
+                                             CFSTR("reach target %p: SCNetworkReachability server failure, retry schedule"),
+                                             target);
+                                       retry = TRUE;
+                                       break;
+                               default : {
+                                       SCLog(TRUE, LOG_ERR, CFSTR("%s  target schedule failed"),
+                                             targetPrivate->log_prefix);
+                                       log_xpc_object("  reply", reply);
+                               }
+                       }
+
+                       if (ok) {
+                               CFRetain(target);
+                       }
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("SCNetworkReachability server not available"));
+                       serverAvailable = FALSE;
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) {
+                       SCLog(TRUE, LOG_DEBUG,
+                             CFSTR("reach target %p: SCNetworkReachability server failure, retry schedule"),
+                             target);
+                       retry = TRUE;
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("reach target %p: _targetSchedule with unexpected reply"),
+                             target);
+                       log_xpc_object("  reply", reply);
+               }
+
+               xpc_release(reply);
+       }
+
+       if (retry) {
+               // reconnect
+               _reach_server_target_reconnect(connection, target);
+
+               // and retry
+               retry = FALSE;
+               goto retry;
+       }
+
+       xpc_release(reqdict);
+       return ok;
+}
+
+
+static void
+_reach_reply_set_reachability(SCNetworkReachabilityRef target,
+                             xpc_object_t              reply)
+{
+       char                            *if_name;
+       size_t                          len             = 0;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       targetPrivate->serverInfo.cycle = xpc_dictionary_get_uint64(reply,
+                                                                   REACH_STATUS_CYCLE);
+
+       targetPrivate->serverInfo.flags = xpc_dictionary_get_uint64(reply,
+                                                                   REACH_STATUS_FLAGS);
+
+       targetPrivate->serverInfo.if_index = xpc_dictionary_get_uint64(reply,
+                                                                      REACH_STATUS_IF_INDEX);
+
+       bzero(&targetPrivate->serverInfo.if_name, sizeof(targetPrivate->serverInfo.if_name));
+       if_name = (void *)xpc_dictionary_get_data(reply,
+                                                 REACH_STATUS_IF_NAME,
+                                                 &len);
+       if ((if_name != NULL) && (len > 0)) {
+               if (len > sizeof(targetPrivate->serverInfo.if_name)) {
+                       len = sizeof(targetPrivate->serverInfo.if_name);
+               }
+
+               bcopy(if_name, targetPrivate->serverInfo.if_name, len);
+       }
+
+       targetPrivate->serverInfo.sleeping = xpc_dictionary_get_bool(reply,
+                                                                    REACH_STATUS_SLEEPING);
+
+       if (targetPrivate->type == reachabilityTypeName) {
+               xpc_object_t            addresses;
+
+               if (targetPrivate->resolvedAddress != NULL) {
+                       CFRelease(targetPrivate->resolvedAddress);
+                       targetPrivate->resolvedAddress = NULL;
+               }
+
+               targetPrivate->resolvedAddressError = xpc_dictionary_get_int64(reply,
+                                                                              REACH_STATUS_RESOLVED_ADDRESS_ERROR);
+
+               addresses = xpc_dictionary_get_value(reply, REACH_STATUS_RESOLVED_ADDRESS);
+               if ((addresses != NULL) && (xpc_get_type(addresses) != XPC_TYPE_ARRAY)) {
+                       addresses = NULL;
+               }
+
+               if ((targetPrivate->resolvedAddressError == 0) && (addresses != NULL)) {
+                       int                     i;
+                       int                     n;
+                       CFMutableArrayRef       newAddresses;
+
+                       newAddresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+                       n = xpc_array_get_count(addresses);
+                       for (i = 0; i < n; i++) {
+                               struct addrinfo *sa;
+                               size_t          len;
+                               CFDataRef       newAddress;
+
+                               sa = (struct addrinfo *)xpc_array_get_data(addresses, i, &len);
+                               newAddress = CFDataCreate(NULL, (const UInt8 *)sa, len);
+                               CFArrayAppendValue(newAddresses, newAddress);
+                               CFRelease(newAddress);
+                       }
+
+                       targetPrivate->resolvedAddress = newAddresses;
+               } else {
+                       /* save the error associated with the attempt to resolve the name */
+                       targetPrivate->resolvedAddress = CFRetain(kCFNull);
+               }
+               targetPrivate->needResolve = FALSE;
+       }
+
+       return;
+}
+
+
+__private_extern__
+Boolean
+_reach_server_target_status(xpc_connection_t connection, SCNetworkReachabilityRef target)
+{
+       Boolean                         ok              = FALSE;
+       xpc_object_t                    reply;
+       xpc_object_t                    reqdict;
+       Boolean                         retry           = FALSE;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       if (_sc_debug) {
+               CFStringRef     str;
+
+               str = _SCNetworkReachabilityCopyTargetDescription(target);
+               SCLog(TRUE, LOG_INFO, CFSTR("%scheckReachability(%@)"),
+                     targetPrivate->log_prefix,
+                     str);
+               CFRelease(str);
+       }
+
+       // create message
+       reqdict = xpc_dictionary_create(NULL, NULL, 0);
+
+       // set request
+       xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_STATUS);
+
+       // add the target [ID]
+       xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target);
+
+    retry :
+
+       reply = xpc_connection_send_message_with_reply_sync(connection, reqdict);
+       if (reply != NULL) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(reply);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       int64_t         status;
+
+                       status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY);
+                       switch (status) {
+                               case REACH_REQUEST_REPLY_OK :
+                                       ok = TRUE;
+                                       break;
+                               case REACH_REQUEST_REPLY_UNKNOWN :
+                                       SCLog(TRUE, LOG_DEBUG,
+                                             CFSTR("reach target %p: SCNetworkReachability server failure, retry status"),
+                                             target);
+                                       retry = TRUE;
+                                       break;
+                               default :
+                                       SCLog(TRUE, LOG_INFO, CFSTR("%s  target status failed"),
+                                             targetPrivate->log_prefix);
+                                       log_xpc_object("  reply", reply);
+                       }
+
+                       if (ok) {
+                               _reach_reply_set_reachability(target, reply);
+
+                               if (_sc_debug) {
+                                       SCLog(TRUE, LOG_INFO, CFSTR("%s  flags     = 0x%08x"),
+                                             targetPrivate->log_prefix,
+                                             targetPrivate->serverInfo.flags);
+                                       if (targetPrivate->serverInfo.if_index != 0) {
+                                               SCLog(TRUE, LOG_INFO, CFSTR("%s  device    = %s (%hu%s)"),
+                                                     targetPrivate->log_prefix,
+                                                     targetPrivate->serverInfo.if_name,
+                                                     targetPrivate->serverInfo.if_index,
+                                                     targetPrivate->serverInfo.sleeping ? ", z" : "");
+                                       }
+                                       if (targetPrivate->serverInfo.cycle != targetPrivate->cycle) {
+                                               SCLog(TRUE, LOG_INFO, CFSTR("%s  forced"),
+                                                     targetPrivate->log_prefix);
+                                       }
+                               }
+                       }
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("SCNetworkReachability server not available"));
+                       serverAvailable = FALSE;
+                       ok = TRUE;
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) {
+                       SCLog(TRUE, LOG_DEBUG,
+                             CFSTR("reach target %p: SCNetworkReachability server failure, retry status"),
+                             target);
+                       retry = TRUE;
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("reach target %p: _targetStatus with unexpected reply"),
+                             target);
+                       log_xpc_object("  reply", reply);
+               }
+
+               xpc_release(reply);
+       }
+
+       if (retry) {
+               // reconnect
+               _reach_server_target_reconnect(connection, target);
+
+               // and retry
+               retry = FALSE;
+               goto retry;
+       }
+
+       xpc_release(reqdict);
+       return ok;
+}
+
+
+static Boolean
+_reach_server_target_unschedule(xpc_connection_t connection, SCNetworkReachabilityRef target)
+{
+       Boolean                         ok              = FALSE;
+       xpc_object_t                    reply;
+       xpc_object_t                    reqdict;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       // create message
+       reqdict = xpc_dictionary_create(NULL, NULL, 0);
+
+       // set request
+       xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_UNSCHEDULE);
+
+       // add the target [ID]
+       xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target);
+
+       reply = xpc_connection_send_message_with_reply_sync(connection, reqdict);
+       if (reply != NULL) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(reply);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       int64_t         status;
+
+                       status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY);
+                       switch (status) {
+                               case REACH_REQUEST_REPLY_OK :
+                                       ok = TRUE;
+                                       break;
+                               case REACH_REQUEST_REPLY_UNKNOWN :
+                                       SCLog(TRUE, LOG_DEBUG,
+                                             CFSTR("reach target %p: SCNetworkReachability server failure, no need to unschedule"),
+                                             target);
+                                       break;
+                               default :
+                                       SCLog(TRUE, LOG_INFO, CFSTR("%s  target unschedule failed"),
+                                             targetPrivate->log_prefix);
+                                       log_xpc_object("  reply", reply);
+                       }
+
+                       if (ok) {
+                               CFRelease(target);
+                       }
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("SCNetworkReachability server not available"));
+                       serverAvailable = FALSE;
+                       ok = TRUE;
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) {
+                       SCLog(TRUE, LOG_DEBUG,
+                             CFSTR("reach target %p: SCNetworkReachability server failure, no need to unschedule"),
+                             target);
+                       ok = TRUE;
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("reach target %p: _targetUnschedule with unexpected reply"),
+                             target);
+                       log_xpc_object("  reply", reply);
+               }
+
+               xpc_release(reply);
+       }
+
+       xpc_release(reqdict);
+       return ok;
+}
+
+
+#pragma mark -
+#pragma mark Reconnect
+
+
+static void
+_reach_server_target_reconnect(xpc_connection_t connection, SCNetworkReachabilityRef target)
+{
+       Boolean                         ok;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       if (!targetPrivate->serverActive) {
+               // if target already removed
+               return;
+       }
+
+       // server has been restarted
+       targetPrivate->cycle = 0;
+
+       // re-associate with server
+       ok = _reach_server_target_add(connection, target);
+       if (!ok) {
+               // if we could not add the target
+               return;
+       }
+
+       if (!targetPrivate->serverScheduled) {
+               // if not scheduled
+               return;
+       }
+
+       // ... and re-schedule with server
+       ok = _reach_server_target_schedule(connection, target);
+       if (!ok) {
+               // if we could not reschedule the target
+               return;
+       }
+
+       // .. and update our status
+       __SCNetworkReachabilityPerformNoLock(target);
+
+       return;
+}
+
+
+static void
+_reach_connection_reconnect(xpc_connection_t connection)
+{
+       dispatch_queue_t        q;
+
+       q = _reach_requests_rbt_queue();
+       dispatch_sync(q, ^{
+               struct rb_node          *rbn;
+               struct rb_tree          *rbt;
+
+               rbt = _reach_requests_rbt();
+               rbn = rb_tree_iterate(rbt, NULL, RB_DIR_RIGHT);
+               for ( ; rbn != NULL ; rbn = rb_tree_iterate(rbt, rbn, RB_DIR_LEFT)) {
+                       reach_request_t                 *rbt_request;
+                       SCNetworkReachabilityRef        target;
+
+                       rbt_request = RBNODE_TO_REACH_REQUEST(rbn);
+
+                       target = rbt_request->target;
+                       CFRetain(target);
+                       dispatch_async(__SCNetworkReachability_concurrent_queue(), ^{
+                               _reach_server_target_reconnect(connection, target);
+                               CFRelease(target);
+                       });
+               }
+       });
+
+       return;
+}
+
+
+#pragma mark -
+#pragma mark SPI (exposed)
+
+
+Boolean
+_SCNetworkReachabilityServer_snapshot(void)
+{
+       xpc_connection_t        c;
+       Boolean                 ok      = FALSE;
+       xpc_object_t            reply;
+       xpc_object_t            reqdict;
+
+       // initialize connection with SCNetworkReachability server
+       c = _reach_connection();
+       if (c == NULL) {
+               return FALSE;
+       }
+
+       // create message
+       reqdict = xpc_dictionary_create(NULL, NULL, 0);
+
+       // set request
+       xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_SNAPSHOT);
+
+       // add the process name (for debugging)
+       add_proc_name(reqdict);
+
+    retry :
+
+       // send request
+       reply = xpc_connection_send_message_with_reply_sync(c, reqdict);
+       if (reply != NULL) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(reply);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       int64_t         status;
+
+                       status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY);
+                       ok = (status == REACH_REQUEST_REPLY_OK);
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("SCNetworkReachability server not available"));
+                       serverAvailable = FALSE;
+               } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) {
+                       SCLog(TRUE, LOG_DEBUG,
+                             CFSTR("SCNetworkReachability server failure, retrying"));
+                       xpc_release(reply);
+                       goto retry;
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("_snapshot with unexpected reply"));
+                       log_xpc_object("  reply", reply);
+               }
+
+               xpc_release(reply);
+       }
+
+       xpc_release(reqdict);
+       return ok;
+}
+
+
+__private_extern__
+Boolean
+__SCNetworkReachabilityServer_targetAdd(SCNetworkReachabilityRef target)
+{
+       xpc_connection_t                c;
+       Boolean                         ok;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       c = _reach_connection();
+       if (c == NULL) {
+               return FALSE;
+       }
+
+       ok = _reach_server_target_add(c, target);
+       if (ok) {
+               _SC_ATOMIC_CMPXCHG(&targetPrivate->serverActive, FALSE, TRUE);
+       }
+
+       return ok;
+}
+
+
+__private_extern__
+void
+__SCNetworkReachabilityServer_targetRemove(SCNetworkReachabilityRef target)
+{
+       xpc_connection_t                c;
+       Boolean                         ok;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       if (!targetPrivate->serverActive) {
+               // if not active
+               return;
+       }
+
+       c = _reach_connection();
+       if (c == NULL) {
+               return;
+       }
+
+       ok = _reach_server_target_remove(c, target);
+       if (ok) {
+               _SC_ATOMIC_CMPXCHG(&targetPrivate->serverActive, TRUE, FALSE);
+       }
+
+       return;
+}
+
+
+__private_extern__
+Boolean
+__SCNetworkReachabilityServer_targetSchedule(SCNetworkReachabilityRef target)
+{
+       xpc_connection_t                c;
+       Boolean                         ok;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       c = _reach_connection();
+       if (c == NULL) {
+               return FALSE;
+       }
+
+       _reach_request_add(target);
+       ok = _reach_server_target_schedule(c, target);
+       if (ok) {
+               _SC_ATOMIC_CMPXCHG(&targetPrivate->serverScheduled, FALSE, TRUE);
+       } else {
+               _reach_request_remove(target);
+       }
+
+       return ok;
+}
+
+
+__private_extern__
+Boolean
+__SCNetworkReachabilityServer_targetStatus(SCNetworkReachabilityRef target)
+{
+       xpc_connection_t                c;
+       Boolean                         ok;
+
+       c = _reach_connection();
+       if (c == NULL) {
+               return FALSE;
+       }
+
+       ok = _reach_server_target_status(c, target);
+       return ok;
+}
+
+
+__private_extern__
+Boolean
+__SCNetworkReachabilityServer_targetUnschedule(SCNetworkReachabilityRef target)
+{
+       xpc_connection_t                c;
+       Boolean                         ok;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       if (!targetPrivate->serverScheduled) {
+               // if not scheduled
+               return TRUE;
+       }
+
+       c = _reach_connection();
+       if (c == NULL) {
+               return FALSE;
+       }
+
+       ok = _reach_server_target_unschedule(c, target);
+       if (ok) {
+               _SC_ATOMIC_CMPXCHG(&targetPrivate->serverScheduled, TRUE, FALSE);
+               _reach_request_remove(target);
+       } else {
+               // if unschedule failed
+       }
+
+       return ok;
+}
+
+#endif // HAVE_REACHABILITY_SERVER
diff --git a/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_server.c b/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_server.c
new file mode 100644 (file)
index 0000000..27753af
--- /dev/null
@@ -0,0 +1,2033 @@
+/*
+ * Copyright (c) 2011, 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <SystemConfiguration/SCPrivate.h>
+#include "SCNetworkReachabilityInternal.h"
+
+#ifdef HAVE_REACHABILITY_SERVER
+
+#include <fcntl.h>
+#include <paths.h>
+#include <CommonCrypto/CommonDigest.h>
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#include <xpc/xpc.h>
+#include <xpc/private.h>
+
+#include "rb.h"
+
+
+#pragma mark -
+#pragma mark Globals
+
+
+/*
+ * S_debug
+ *   A boolean that enables additional logging.
+ */
+static boolean_t       S_debug         = FALSE;
+
+
+#pragma mark -
+#pragma mark Support functions
+
+
+static void
+log_xpc_object(const char *msg, xpc_object_t obj)
+{
+       char            *desc;
+
+       desc = xpc_copy_description(obj);
+       SCLog(S_debug, LOG_INFO, CFSTR("%s = %s"), msg, desc);
+       free(desc);
+}
+
+
+static __inline__ void
+my_CFDictionaryApplyFunction(CFDictionaryRef                   theDict,
+                            CFDictionaryApplierFunction        applier,
+                            void                               *context)
+{
+       CFAllocatorRef  myAllocator;
+       CFDictionaryRef myDict;
+
+       myAllocator = CFGetAllocator(theDict);
+       myDict      = CFDictionaryCreateCopy(myAllocator, theDict);
+       CFDictionaryApplyFunction(myDict, applier, context);
+       CFRelease(myDict);
+       return;
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkReachability target support
+
+
+static CFMutableDictionaryRef  reach_digest_map;
+
+
+static dispatch_queue_t
+_server_concurrent_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create(REACH_SERVICE_NAME ".concurrent",
+                                         DISPATCH_QUEUE_CONCURRENT);
+               dispatch_queue_set_width(q, 32);
+       });
+
+       return q;
+}
+
+
+static dispatch_queue_t
+_server_digest_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create(REACH_SERVICE_NAME ".digest", NULL);
+       });
+
+       return q;
+}
+
+
+static dispatch_group_t
+_target_group(SCNetworkReachabilityRef target)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       return targetPrivate->serverGroup;
+}
+
+
+static dispatch_queue_t
+_target_queue(SCNetworkReachabilityRef target)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       return targetPrivate->serverQueue;
+}
+
+
+#pragma mark -
+
+
+/*
+ * _target_reference_add
+ *
+ * Note: use dispatch_sync(_server_digest_queue(), ^{ ... });
+ */
+static void
+_target_reference_add(SCNetworkReachabilityRef target, CFDataRef digest, xpc_connection_t connection)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       // take a reference to the target
+       CFRetain(target);
+
+       // ensure that we have a dispatch group
+       if (targetPrivate->serverGroup == NULL) {
+               targetPrivate->serverGroup = dispatch_group_create();
+       }
+
+       // ensure that we have a dispatch queue
+       if (targetPrivate->serverQueue == NULL) {
+               char    qname[256];
+
+               snprintf(qname, sizeof(qname), "com.apple.SCNetworkReachability.%p.server", target);
+               targetPrivate->serverQueue = dispatch_queue_create(qname, NULL);
+       }
+
+       // bump the reference count
+       if (_SC_ATOMIC_INC(&targetPrivate->serverReferences) == 0) {
+               // and maintain a digest-->target mapping
+               targetPrivate->serverDigest = CFRetain(digest);
+               CFDictionarySetValue(reach_digest_map, digest, target);
+       }
+
+       if (S_debug) {
+               CFStringRef     str;
+
+               str = _SCNetworkReachabilityCopyTargetDescription(target);
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p>   target %p: reference added (%@, %d)"),
+                     connection,
+                     target,
+                     str,
+                     targetPrivate->serverReferences);
+               CFRelease(str);
+       }
+
+       return;
+}
+
+
+/*
+ * _target_reference_remove
+ *
+ * Note: use dispatch_sync(_server_digest_queue(), ^{ ... });
+ */
+static void
+_target_reference_remove(SCNetworkReachabilityRef target, xpc_connection_t connection)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       // drop the reference count
+       if (_SC_ATOMIC_DEC(&targetPrivate->serverReferences) == 0) {
+               /*
+                * if that was the last reference, we no longer need to
+                * keep the digest-->target mapping
+                */
+               CFDictionaryRemoveValue(reach_digest_map, targetPrivate->serverDigest);
+               CFRelease(targetPrivate->serverDigest);
+               targetPrivate->serverDigest = NULL;
+       }
+
+       if (S_debug) {
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p>   target %p: reference removed (%d)"),
+                     connection,
+                     target,
+                     targetPrivate->serverReferences);
+       }
+
+       // release a reference to the target
+       CFRelease(target);
+
+       return;
+}
+
+
+#pragma mark -
+
+
+#define        MUTEX_LOCK(m) {                                                 \
+       int _lock_ = (pthread_mutex_lock(m) == 0);                      \
+       assert(_lock_);                                                 \
+}
+
+#define        MUTEX_UNLOCK(m) {                                               \
+       int _unlock_ = (pthread_mutex_unlock(m) == 0);                  \
+       assert(_unlock_);                                               \
+}
+
+
+static void
+_target_reply_add_reachability(SCNetworkReachabilityRef target,
+                              xpc_object_t             reply)
+{
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       MUTEX_LOCK(&targetPrivate->lock);
+
+       xpc_dictionary_set_uint64(reply,
+                                 REACH_STATUS_CYCLE,
+                                 targetPrivate->info.cycle);
+       xpc_dictionary_set_uint64(reply,
+                                 REACH_STATUS_FLAGS,
+                                 targetPrivate->info.flags);
+       xpc_dictionary_set_uint64(reply,
+                                 REACH_STATUS_IF_INDEX,
+                                 targetPrivate->info.if_index);
+       xpc_dictionary_set_data  (reply,
+                                 REACH_STATUS_IF_NAME,
+                                 targetPrivate->info.if_name,
+                                 sizeof(targetPrivate->info.if_name));
+       xpc_dictionary_set_bool  (reply,
+                                 REACH_STATUS_SLEEPING,
+                                 targetPrivate->info.sleeping);
+       if (targetPrivate->type == reachabilityTypeName) {
+               if (isA_CFArray(targetPrivate->resolvedAddress)) {
+                       xpc_object_t    addresses;
+                       CFIndex         i;
+                       CFIndex         n;
+
+                       addresses = xpc_array_create(NULL, 0);
+
+                       n = CFArrayGetCount(targetPrivate->resolvedAddress);
+                       for (i = 0; i < n; i++) {
+                               CFDataRef       address;
+
+                               address = CFArrayGetValueAtIndex(targetPrivate->resolvedAddress, i);
+                               xpc_array_set_data(addresses,
+                                                  XPC_ARRAY_APPEND,
+                                                  CFDataGetBytePtr(address),
+                                                  CFDataGetLength(address));
+                       }
+
+                       xpc_dictionary_set_value(reply,
+                                                REACH_STATUS_RESOLVED_ADDRESS,
+                                                addresses);
+                       xpc_release(addresses);
+               }
+               xpc_dictionary_set_int64(reply,
+                                        REACH_STATUS_RESOLVED_ADDRESS_ERROR,
+                                        targetPrivate->resolvedAddressError);
+       }
+
+       MUTEX_UNLOCK(&targetPrivate->lock);
+
+       return;
+}
+
+
+#pragma mark -
+
+
+typedef struct {
+       xpc_connection_t        connection;
+       uint64_t                target_id;
+} reach_watcher_key_t;
+
+typedef struct {
+       unsigned int            n_changes;
+} reach_watcher_val_t;
+
+
+static CFDataRef
+_target_watcher_key_create(xpc_connection_t    connection,
+                          uint64_t             target_id)
+{
+       CFDataRef               key;
+       reach_watcher_key_t     watcher_key;
+
+       watcher_key.connection = connection;
+       watcher_key.target_id  = target_id;
+
+       key = CFDataCreate(NULL, (UInt8 *)&watcher_key, sizeof(watcher_key));
+       return key;
+}
+
+
+static Boolean
+_target_watcher_add(SCNetworkReachabilityRef   target,
+                   xpc_connection_t            connection,
+                   uint64_t                    target_id)
+{
+       __block Boolean         ok      = TRUE;
+       dispatch_queue_t        q;
+
+       q = _target_queue(target);
+       dispatch_sync(q, ^{
+               CFDataRef                       key;
+               SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+               if (targetPrivate->serverWatchers == NULL) {
+                       ok = SCNetworkReachabilitySetDispatchQueue(target, q);
+                       if (!ok) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("<%p> target %p: _watcher_add SCNetworkReachabilitySetDispatchQueue() failed: %s"),
+                                     connection,
+                                     target,
+                                     SCErrorString(SCError()));
+                               return;
+                       }
+
+                       targetPrivate->serverWatchers = CFDictionaryCreateMutable(NULL,
+                                                                                 0,
+                                                                                 &kCFTypeDictionaryKeyCallBacks,
+                                                                                 &kCFTypeDictionaryValueCallBacks);
+               }
+
+               xpc_retain(connection);
+
+               key = _target_watcher_key_create(connection, target_id);
+               if (CFDictionaryContainsKey(targetPrivate->serverWatchers, key)) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("<%p>   target %p: watcher not added, c=0x%0llx, \"serverWatchers\" key exists"),
+                             connection,
+                             target,
+                             target_id);
+               } else {
+                       CFDataRef                               val;
+                       static const reach_watcher_val_t        watcher_val0    = { 0 };
+
+                       val = CFDataCreate(NULL, (UInt8 *)&watcher_val0, sizeof(watcher_val0));
+                       CFDictionaryAddValue(targetPrivate->serverWatchers, key, val);
+                       CFRelease(val);
+
+                       if (S_debug) {
+                               SCLog(TRUE, LOG_INFO,
+                                     CFSTR("<%p>   target %p: watcher added, c=0x%0llx, n=%d"),
+                                     connection,
+                                     target,
+                                     target_id,
+                                     CFDictionaryGetCount(targetPrivate->serverWatchers));
+                       }
+               }
+               CFRelease(key);
+       });
+
+       return ok;
+}
+
+
+static Boolean
+_target_watcher_checkin(SCNetworkReachabilityRef       target,
+                       xpc_connection_t                connection,
+                       uint64_t                        target_id)
+{
+       __block Boolean         scheduled       = FALSE;
+
+       dispatch_sync(_target_queue(target), ^{
+               CFDataRef                       key;
+               unsigned int                    n;
+               SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+               CFDataRef                       val;
+               reach_watcher_val_t             *watcher_val;
+
+               if (targetPrivate->serverWatchers == NULL) {
+                       // if no watchers
+                       return;
+               }
+
+               key = _target_watcher_key_create(connection, target_id);
+               val = CFDictionaryGetValue(targetPrivate->serverWatchers, key);
+               CFRelease(key);
+               if (val == NULL) {
+                       // if the target [for this client] was not scheduled
+                       return;
+               }
+
+               // indicate that the target was scheduled
+               scheduled = TRUE;
+
+               /*
+                * and note that the reachability flags for this target have
+                * been picked up by the client
+                */
+               /* ALIGN: CF aligns to at least >8 byte boundries */
+               watcher_val = (reach_watcher_val_t *)(void *)CFDataGetBytePtr(val);
+               n = _SC_ATOMIC_ZERO(&watcher_val->n_changes);
+               if (S_debug && (n > 0)) {
+                       SCLog(TRUE, LOG_INFO,
+                             CFSTR("<%p> target %p: SCNetworkReachabilityGetFlags() after %d notification%s"),
+                             connection,
+                             target,
+                             n,
+                             (n == 1) ? "" : "s");
+               }
+       });
+
+       return scheduled;
+}
+
+
+static Boolean
+_target_watcher_remove(SCNetworkReachabilityRef        target,
+                      xpc_connection_t         connection,
+                      uint64_t                 target_id)
+{
+       __block Boolean         ok      = TRUE;
+
+       dispatch_sync(_target_queue(target), ^{
+               CFDataRef                       key;
+               CFIndex                         n;
+               SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+               if (targetPrivate->serverWatchers == NULL) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("<%p>   target %p: watcher not removed, c=0x%0llx, no \"serverWatchers\""),
+                             connection,
+                             target,
+                             target_id);
+                       return;
+               }
+
+               key = _target_watcher_key_create(connection, target_id);
+               if (!CFDictionaryContainsKey(targetPrivate->serverWatchers, key)) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("<%p>   target %p: watcher not removed, c=0x%0llx, no \"serverWatchers\" key"),
+                             connection,
+                             target,
+                             target_id);
+                       CFRelease(key);
+                       return;
+               }
+
+               CFDictionaryRemoveValue(targetPrivate->serverWatchers, key);
+               xpc_release(connection);
+               CFRelease(key);
+
+               n = CFDictionaryGetCount(targetPrivate->serverWatchers);
+
+               if (S_debug) {
+                       SCLog(TRUE, LOG_INFO,
+                             CFSTR("<%p>   target %p: watcher removed, c=0x%0llx, n=%d"),
+                             connection,
+                             target,           // server
+                             target_id,        // client
+                             n);
+               }
+
+               if (n == 0) {
+                       CFRelease(targetPrivate->serverWatchers);
+                       targetPrivate->serverWatchers = NULL;
+
+                       ok = SCNetworkReachabilitySetDispatchQueue(target, NULL);
+                       if (!ok) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("<%p> target %p: _watcher_remove SCNetworkReachabilitySetDispatchQueue() failed: %s"),
+                                     connection,
+                                     target,
+                                     SCErrorString(SCError()));
+                               return;
+                       }
+
+                       // no more watchers, flags are no longer valid
+                       (void) _SC_ATOMIC_CMPXCHG(&targetPrivate->serverInfoValid, TRUE, FALSE);
+               }
+       });
+
+       return ok;
+}
+
+
+#pragma mark -
+#pragma mark Reachability [RBT] client support
+
+
+typedef struct {
+       struct rb_node          rbn;
+       xpc_connection_t        connection;
+       pid_t                   pid;
+       const char              *proc_name;
+       CFMutableDictionaryRef  targets;        // target_id --> SCNetworkReachabilityRef
+} reach_client_t;
+
+
+#define RBNODE_TO_REACH_CLIENT(node) \
+       ((reach_client_t *)((uintptr_t)node - offsetof(reach_client_t, rbn)))
+
+
+static int
+_rbt_compare_transaction_nodes(const struct rb_node *n1, const struct rb_node *n2)
+{
+       uint64_t        a = (uintptr_t)RBNODE_TO_REACH_CLIENT(n1)->connection;
+       uint64_t        b = (uintptr_t)RBNODE_TO_REACH_CLIENT(n2)->connection;
+
+       return (a - b);
+}
+
+
+static int
+_rbt_compare_transaction_key(const struct rb_node *n1, const void *key)
+{
+       uint64_t        a = (uintptr_t)RBNODE_TO_REACH_CLIENT(n1)->connection;
+       uint64_t        b = *(uintptr_t *)key;
+
+       return (a - b);
+}
+
+
+static struct rb_tree *
+_reach_clients_rbt()
+{
+       static dispatch_once_t          once;
+       static const struct rb_tree_ops ops = {
+               .rbto_compare_nodes     = _rbt_compare_transaction_nodes,
+               .rbto_compare_key       = _rbt_compare_transaction_key,
+       };
+       static struct rb_tree           rbtree;
+
+       dispatch_once(&once, ^{
+               rb_tree_init(&rbtree, &ops);
+       });
+
+       return &rbtree;
+}
+
+
+static dispatch_queue_t
+_reach_connection_queue()
+{
+       static dispatch_once_t  once;
+       static dispatch_queue_t q;
+
+       dispatch_once(&once, ^{
+               q = dispatch_queue_create(REACH_SERVICE_NAME ".connection", NULL);
+       });
+
+       return q;
+}
+
+
+static reach_client_t *
+_reach_client_create(xpc_connection_t connection)
+{
+       reach_client_t  *client;
+
+       client = calloc(1, sizeof(*client));
+       client->connection = connection;
+       client->pid = xpc_connection_get_pid(connection);
+       client->proc_name = NULL;
+       client->targets = CFDictionaryCreateMutable(NULL,
+                                                   0,
+                                                   &kCFTypeDictionaryKeyCallBacks,
+                                                   &kCFTypeDictionaryValueCallBacks);
+
+       return client;
+}
+
+
+static void
+_reach_client_release(reach_client_t *client)
+{
+       if (client->proc_name != NULL) {
+               free((void *)client->proc_name);
+       }
+       CFRelease(client->targets);
+       free(client);
+       return;
+}
+
+
+static void
+_reach_client_remove_target(const void *key, const void *value, void *context)
+{
+       xpc_connection_t                connection      = (xpc_connection_t)context;
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)value;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       // check if we have anyone watching this target
+       if (targetPrivate->serverWatchers != NULL) {
+               CFIndex         n;
+
+               n = CFDictionaryGetCount(targetPrivate->serverWatchers);
+               if (n > 0) {
+                       CFIndex         i;
+                       const void *    watchers_q[32];
+                       const void **   watchers        = watchers_q;
+
+                       if (n > sizeof(watchers_q)/sizeof(watchers[0])) {
+                               watchers = CFAllocatorAllocate(NULL, n * sizeof(CFDataRef), 0);
+                       }
+                       CFDictionaryGetKeysAndValues(targetPrivate->serverWatchers, watchers, NULL);
+
+                       for (i = 0; i < n; i++) {
+                               CFDataRef               key;
+                               reach_watcher_key_t     *watcher_key;
+
+                               key = (CFDataRef)watchers[i];
+                               /* ALIGN: CF aligns to >8 byte boundries */
+                               watcher_key = (reach_watcher_key_t *)(void *)CFDataGetBytePtr(key);
+                               if (watcher_key->connection == connection) {
+                                       // remove watcher references for THIS connection
+                                       _target_watcher_remove(target,
+                                                              watcher_key->connection,
+                                                              watcher_key->target_id);
+                               }
+                       }
+
+                       if (watchers != watchers_q) {
+                               CFAllocatorDeallocate(NULL, watchers);
+                       }
+               }
+       }
+
+       // remove our reference to this target
+       dispatch_sync(_server_digest_queue(), ^{
+               _target_reference_remove(target, connection);
+       });
+
+       return;
+}
+
+
+static void
+_reach_client_remove(xpc_connection_t connection)
+{
+       struct rb_tree  *rbtree = _reach_clients_rbt();
+       struct rb_node  *rbn;
+
+       rbn = rb_tree_find_node(rbtree, &connection);
+       if (rbn != NULL) {
+               reach_client_t  *client;
+
+               client = RBNODE_TO_REACH_CLIENT(rbn);
+
+               // remove any remaining target references (for this client)
+               my_CFDictionaryApplyFunction(client->targets,
+                                            _reach_client_remove_target,
+                                            (void *)connection);
+
+               rb_tree_remove_node(rbtree, rbn);
+               _reach_client_release(client);
+       } else {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p> _reach_client_remove: unexpected client"),
+                     connection);
+       }
+
+       return;
+}
+
+
+static __inline__ CFDataRef
+_client_target_key_create(uint64_t target_id)
+{
+       CFDataRef       target_key;
+
+       target_key = CFDataCreate(NULL, (UInt8 *)&target_id, sizeof(target_id));
+       return target_key;
+}
+
+
+static SCNetworkReachabilityRef
+_client_target_copy(reach_client_t *client, uint64_t target_id)
+{
+       SCNetworkReachabilityRef        target;
+       CFDataRef                       target_key;
+
+       target_key = _client_target_key_create(target_id);
+       target = CFDictionaryGetValue(client->targets, target_key);
+       CFRelease(target_key);
+
+       if (target != NULL) {
+               CFRetain(target);
+       }
+
+       return target;
+}
+
+
+static Boolean
+_client_target_set(reach_client_t *client, uint64_t target_id, SCNetworkReachabilityRef target)
+{
+       Boolean         added;
+       CFDataRef       target_key;
+
+       target_key = _client_target_key_create(target_id);
+       added = !CFDictionaryContainsKey(client->targets, target_key);
+       if (added) {
+               CFDictionarySetValue(client->targets, target_key, target);
+       }
+       CFRelease(target_key);
+
+       return added;
+}
+
+
+static void
+_client_target_remove(reach_client_t *client, uint64_t target_id)
+{
+       CFDataRef       target_key;
+
+       target_key = _client_target_key_create(target_id);
+       CFDictionaryRemoveValue(client->targets, target_key);
+       CFRelease(target_key);
+
+       return;
+}
+
+
+#pragma mark -
+#pragma mark Reachability [XPC] server functions
+
+/*
+ * _reach_changed
+ *
+ * Note: should be exec'd on the target queue
+ */
+static void
+_reach_changed(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
+{
+       CFIndex                         i;
+       CFIndex                         n;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+       const void *                    watcher_keys_q[32];
+       const void **                   watcher_keys    = watcher_keys_q;
+       const void *                    watcher_vals_q[32];
+       const void **                   watcher_vals    = watcher_vals_q;
+
+       if (S_debug) {
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("%sprocess reachability changed, flags = 0x%08x"),
+                     targetPrivate->log_prefix,
+                     flags);
+       }
+
+       if (targetPrivate->serverWatchers == NULL) {
+               // if no watchers
+               return;
+       }
+
+       n = CFDictionaryGetCount(targetPrivate->serverWatchers);
+       if (n == 0) {
+               // if no watchers
+               return;
+       }
+
+       /*
+        * Because we are actively watching for additional changes
+        * we mark the flags as "valid"
+        */
+       if (_SC_ATOMIC_CMPXCHG(&targetPrivate->serverInfoValid, FALSE, TRUE)) {
+               if (S_debug) {
+                       SCLog(TRUE, LOG_INFO, CFSTR("  flags are now \"valid\""));
+               }
+       }
+
+       // notify all of the watchers
+       if (n > sizeof(watcher_keys_q)/sizeof(watcher_keys[0])) {
+               watcher_keys = CFAllocatorAllocate(NULL, n * sizeof(CFDataRef), 0);
+               watcher_vals = CFAllocatorAllocate(NULL, n * sizeof(CFDataRef), 0);
+       }
+
+       CFDictionaryGetKeysAndValues(targetPrivate->serverWatchers,
+                                    watcher_keys,
+                                    watcher_vals);
+
+       for (i = 0; i < n; i++) {
+               xpc_connection_t        connection;
+               CFDataRef               key;
+               uint64_t                target_id;
+               CFDataRef               val;
+               reach_watcher_key_t     *watcher_key;
+               reach_watcher_val_t     *watcher_val;
+
+               val = (CFDataRef)watcher_vals[i];
+               /* ALIGN: CF aligns to >8 byte boundries */
+               watcher_val = (reach_watcher_val_t *)(void *)CFDataGetBytePtr(val);
+
+               if (_SC_ATOMIC_INC(&watcher_val->n_changes) > 0) {
+                       // if we've already sent a notification
+                       continue;
+               }
+
+               key = (CFDataRef)watcher_keys[i];
+               /* ALIGN: CF aligns to >8 byte boundries */
+               watcher_key = (reach_watcher_key_t *)(void *)CFDataGetBytePtr(key);
+
+               connection = xpc_retain(watcher_key->connection);
+               target_id  = watcher_key->target_id;
+               dispatch_async(_reach_connection_queue(), ^{
+                       xpc_object_t    reply;
+
+                       // create our [async] notification
+                       reply = xpc_dictionary_create(NULL, NULL, 0);
+
+                       // set notification
+                       xpc_dictionary_set_int64(reply,
+                                                MESSAGE_NOTIFY,
+                                                MESSAGE_REACHABILITY_STATUS);
+
+                       // set target ID
+                       xpc_dictionary_set_uint64(reply,
+                                                 REACH_CLIENT_TARGET_ID,
+                                                 target_id);
+
+                       log_xpc_object("  reply [async]", reply);
+                       xpc_connection_send_message(connection, reply);
+
+                       xpc_release(reply);
+                       xpc_release(connection);
+               });
+       }
+
+       if (n > sizeof(watcher_keys_q)/sizeof(watcher_keys[0])) {
+               CFAllocatorDeallocate(NULL, watcher_keys);
+               CFAllocatorDeallocate(NULL, watcher_vals);
+       }
+
+       return;
+}
+
+
+static void
+sanitize_address(const struct sockaddr *from, struct sockaddr *to)
+{
+       switch (from->sa_family) {
+               case AF_INET : {
+                       /* ALIGN: cast okay, alignment not assumed. */
+                       struct sockaddr_in *from4       = (struct sockaddr_in *)(void *)from;
+                       struct sockaddr_in *to4         = (struct sockaddr_in *)(void *)to;
+
+                       bzero(to4, sizeof(*to4));
+                       to4->sin_len = sizeof(*to4);
+                       to4->sin_family = AF_INET;
+                       bcopy(&from4->sin_addr, &to4->sin_addr, sizeof(to4->sin_addr));
+                       break;
+               }
+
+               case AF_INET6 : {
+                       /* ALIGN: cast okay, alignment not assumed. */
+                       struct sockaddr_in6 *from6      = (struct sockaddr_in6 *)(void *)from;
+                       struct sockaddr_in6 *to6        = (struct sockaddr_in6 *)(void *)to;
+
+                       bzero(to6, sizeof(*to6));
+                       to6->sin6_len = sizeof(*to6);
+                       to6->sin6_family = AF_INET6;
+                       bcopy(&from6->sin6_addr, &to6->sin6_addr, sizeof(to6->sin6_addr));
+                       to6->sin6_scope_id = from6->sin6_scope_id;
+                       break;
+               }
+
+               default:
+                       bcopy(from, to, from->sa_len);
+                       break;
+       }
+
+       return;
+}
+
+
+static void
+target_add(reach_client_t *client, xpc_object_t request)
+{
+       const char                              *name;
+       const char                              *serv;
+       const struct sockaddr                   *localAddress;
+       struct sockaddr_storage                 localAddress0;
+       const struct sockaddr                   *remoteAddress;
+       struct sockaddr_storage                 remoteAddress0;
+       const struct addrinfo                   *hints;
+       int64_t                                 if_index;
+       const char                              *if_name        = NULL;
+       bool                                    onDemandBypass  = FALSE;
+       uint64_t                                target_id;
+
+
+       unsigned char                           bytes[CC_SHA1_DIGEST_LENGTH];
+       CC_SHA1_CTX                             ctx;
+       CFDataRef                               digest          = NULL;
+       size_t                                  len;
+       xpc_connection_t                        remote;
+       xpc_object_t                            reply;
+       bool                                    resolverBypass  = FALSE;
+       uint64_t                                status          = REACH_REQUEST_REPLY_FAILED;
+
+       Boolean                                 added;
+       __block Boolean                         ok              = TRUE;
+       __block SCNetworkReachabilityRef        target          = NULL;
+
+       if (S_debug) {
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p> create reachability target"),
+                     client->connection);
+//             log_xpc_object("  create", request);
+       }
+
+       remote = xpc_dictionary_get_remote_connection(request);
+       reply = xpc_dictionary_create_reply(request);
+       if (reply == NULL) {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p> target_add: xpc_dictionary_create_reply: failed"),
+                     client->connection);
+               return;
+       }
+
+       target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID);
+       if (target_id == 0) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target ID");
+               goto done;
+       }
+
+       // create a "digest" of the [new] target
+
+       CC_SHA1_Init(&ctx);
+
+       name = xpc_dictionary_get_string(request, REACH_TARGET_NAME);
+       if (name != NULL) {
+               CC_SHA1_Update(&ctx, name, strlen(name));
+       }
+
+       serv = xpc_dictionary_get_string(request, REACH_TARGET_SERV);
+       if (serv != NULL) {
+               CC_SHA1_Update(&ctx, serv, strlen(serv));
+       }
+
+       localAddress = xpc_dictionary_get_data(request, REACH_TARGET_LOCAL_ADDR, &len);
+       if (localAddress != NULL) {
+               if ((len == localAddress->sa_len) && (len <= sizeof(struct sockaddr_storage))) {
+                       sanitize_address(localAddress, (struct sockaddr *)&localAddress0);
+                       CC_SHA1_Update(&ctx, &localAddress0, len);
+               } else {
+                       xpc_dictionary_set_string(reply,
+                                                 REACH_REQUEST_REPLY_DETAIL,
+                                                 "local address: size error");
+                       goto done;
+               }
+       }
+
+       remoteAddress = xpc_dictionary_get_data(request, REACH_TARGET_REMOTE_ADDR, &len);
+       if (remoteAddress != NULL) {
+               if ((len == remoteAddress->sa_len) && (len <= sizeof(struct sockaddr_storage))) {
+                       sanitize_address(remoteAddress, (struct sockaddr *)&remoteAddress0);
+                       CC_SHA1_Update(&ctx, &remoteAddress0, len);
+               } else {
+                       xpc_dictionary_set_string(reply,
+                                                 REACH_REQUEST_REPLY_DETAIL,
+                                                 "remote address: size error");
+                       goto done;
+               }
+       }
+
+       hints = xpc_dictionary_get_data(request, REACH_TARGET_HINTS, &len);
+       if (hints != NULL) {
+               if (len == sizeof(struct addrinfo)) {
+                       CC_SHA1_Update(&ctx, hints, len);
+               } else {
+                       xpc_dictionary_set_string(reply,
+                                                 REACH_REQUEST_REPLY_DETAIL,
+                                                 "hints: size error");
+                       goto done;
+               }
+       }
+
+       if_index = xpc_dictionary_get_int64(request, REACH_TARGET_IF_INDEX);
+       if (if_index != 0) {
+               if_name = xpc_dictionary_get_string(request, REACH_TARGET_IF_NAME);
+               if (if_name != NULL) {
+                       CC_SHA1_Update(&ctx, if_name, strlen(if_name));
+               }
+       }
+
+       onDemandBypass = xpc_dictionary_get_bool(request, REACH_TARGET_ONDEMAND_BYPASS);
+       if (onDemandBypass) {
+               CC_SHA1_Update(&ctx, &onDemandBypass, sizeof(onDemandBypass));
+       }
+
+       resolverBypass = xpc_dictionary_get_bool(request, REACH_TARGET_RESOLVER_BYPASS);
+       if (resolverBypass) {
+               CC_SHA1_Update(&ctx, &resolverBypass, sizeof(resolverBypass));
+       }
+
+
+       CC_SHA1_Final(bytes, &ctx);
+       digest = CFDataCreate(NULL, bytes, sizeof(bytes));
+
+       /*
+        * Check to see if we already have a SCNetworkReachability object
+        * for this digest. If so, we'll share the existing target. If not,
+        * create a new [shared] target.
+        */
+       dispatch_sync(_server_digest_queue(), ^{
+               target = CFDictionaryGetValue(reach_digest_map, digest);
+               if (target != NULL) {
+                       CFRetain(target);
+               } else {
+                       CFDataRef                       data;
+                       CFMutableDictionaryRef          options;
+                       CFStringRef                     str;
+
+                       options = CFDictionaryCreateMutable(NULL,
+                                                           0,
+                                                           &kCFTypeDictionaryKeyCallBacks,
+                                                           &kCFTypeDictionaryValueCallBacks);
+                       if (name != NULL) {
+                               str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
+                               CFRelease(str);
+                       }
+                       if (serv != NULL) {
+                               str = CFStringCreateWithCString(NULL, serv, kCFStringEncodingUTF8);
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionServName, str);
+                               CFRelease(str);
+                       }
+                       if (localAddress != NULL) {
+                               data = CFDataCreate(NULL, (const UInt8 *)&localAddress0, localAddress0.ss_len);
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
+                               CFRelease(data);
+                       }
+                       if (remoteAddress != NULL) {
+                               data = CFDataCreate(NULL, (const UInt8 *)&remoteAddress0, remoteAddress0.ss_len);
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
+                               CFRelease(data);
+                       }
+                       if (hints != NULL) {
+                               data = CFDataCreate(NULL, (const UInt8 *)hints, sizeof(struct addrinfo));
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data);
+                               CFRelease(data);
+                       }
+                       if (onDemandBypass) {
+                               CFDictionarySetValue(options,
+                                                    kSCNetworkReachabilityOptionConnectionOnDemandBypass,
+                                                    kCFBooleanTrue);
+                       }
+                       if (resolverBypass) {
+                               CFDictionarySetValue(options,
+                                                    kSCNetworkReachabilityOptionResolverBypass,
+                                                    kCFBooleanTrue);
+                       }
+                       CFDictionarySetValue(options,
+                                            kSCNetworkReachabilityOptionServerBypass,
+                                            kCFBooleanTrue);
+                       target = SCNetworkReachabilityCreateWithOptions(NULL, options);
+                       CFRelease(options);
+                       if (target == NULL) {
+                               xpc_dictionary_set_string(reply,
+                                                         REACH_REQUEST_REPLY_DETAIL,
+                                                         "SCNetworkReachabilityCreateWithOptions failed");
+                               ok = FALSE;
+                               return;
+                       }
+
+                       // because the interface name may not (no longer) be valid we set
+                       // this after we've created the SCNetworkReachabilty object
+                       if ((if_index != 0) && (if_name != NULL)) {
+                               SCNetworkReachabilityPrivateRef targetPrivate;
+
+                               targetPrivate = (SCNetworkReachabilityPrivateRef)target;
+                               targetPrivate->if_index = if_index;
+                               strlcpy(targetPrivate->if_name, if_name, sizeof(targetPrivate->if_name));
+                       }
+
+
+                       ok = SCNetworkReachabilitySetCallback(target, _reach_changed, NULL);
+                       if (!ok) {
+                               xpc_dictionary_set_string(reply,
+                                                         REACH_REQUEST_REPLY_DETAIL,
+                                                         "SCNetworkReachabilitySetCallback failed");
+                               CFRelease(target);
+                               target = NULL;
+                               return;
+                       }
+               }
+
+               // bump the number of references to this target
+               _target_reference_add(target, digest, client->connection);
+       });
+
+       if (!ok) {
+               goto done;
+       }
+
+       /*
+        * add an association for the client's target_id to the [shared]
+        * SCNetworkReachability object.
+        */
+       added = _client_target_set(client, target_id, target);
+       if (!added) {
+               // if we already had a reference to the target (e.g. reconnect)
+               dispatch_sync(_server_digest_queue(), ^{
+                       _target_reference_remove(target, client->connection);
+               });
+       }
+
+       status = REACH_REQUEST_REPLY_OK;
+
+    done :
+
+       xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status);
+//     log_xpc_object("  reply", reply);
+       xpc_connection_send_message(remote, reply);
+       xpc_release(reply);
+
+       if (digest != NULL) CFRelease(digest);
+       if (target != NULL) CFRelease(target);
+       return;
+}
+
+
+static void
+target_remove(reach_client_t *client, xpc_object_t request)
+{
+       xpc_connection_t                remote;
+       xpc_object_t                    reply;
+       uint64_t                        status          = REACH_REQUEST_REPLY_FAILED;
+       SCNetworkReachabilityRef        target          = NULL;
+       uint64_t                        target_id;
+
+       if (S_debug) {
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p> remove reachability target"),
+                     client->connection);
+//             log_xpc_object("  remove", request);
+       }
+
+       remote = xpc_dictionary_get_remote_connection(request);
+       reply = xpc_dictionary_create_reply(request);
+       if (reply == NULL) {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p> target_remove: xpc_dictionary_create_reply: failed"),
+                     client->connection);
+               return;
+       }
+
+       target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID);
+       if (target_id == 0) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target ID");
+               goto done;
+       }
+
+       target = _client_target_copy(client, target_id);
+       if (target == NULL) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target");
+               status = REACH_REQUEST_REPLY_UNKNOWN;
+               goto done;
+       }
+
+       /*
+        * remove the association from the client's target_id to the [shared]
+        * SCNetworkReachability object.
+        */
+       _client_target_remove(client, target_id);
+
+       // drop the number of references to this target
+       dispatch_sync(_server_digest_queue(), ^{
+               _target_reference_remove(target, client->connection);
+       });
+
+       status = REACH_REQUEST_REPLY_OK;
+
+    done :
+
+       xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status);
+//     log_xpc_object("  reply", reply);
+       xpc_connection_send_message(remote, reply);
+       xpc_release(reply);
+
+       if (target != NULL) CFRelease(target);
+       return;
+}
+
+
+static void
+target_schedule(reach_client_t *client, xpc_object_t request)
+{
+       Boolean                         ok;
+       xpc_connection_t                remote;
+       xpc_object_t                    reply;
+       uint64_t                        status          = REACH_REQUEST_REPLY_FAILED;
+       SCNetworkReachabilityRef        target          = NULL;
+       uint64_t                        target_id;
+
+       if (S_debug) {
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p> schedule reachability target"),
+                     client->connection);
+//             log_xpc_object("  schedule", request);
+       }
+
+       remote = xpc_dictionary_get_remote_connection(request);
+       reply = xpc_dictionary_create_reply(request);
+       if (reply == NULL) {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p> target_schedule: xpc_dictionary_create_reply: failed"),
+                     client->connection);
+               return;
+       }
+
+       target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID);
+       if (target_id == 0) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target ID");
+               goto done;
+       }
+
+       target = _client_target_copy(client, target_id);
+       if (target == NULL) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target");
+               status = REACH_REQUEST_REPLY_UNKNOWN;
+               goto done;
+       }
+
+       // enable monitoring
+       ok = _target_watcher_add(target, client->connection, target_id);
+       if (ok) {
+               status = REACH_REQUEST_REPLY_OK;
+       }
+
+    done :
+
+       xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status);
+//     log_xpc_object("  reply", reply);
+       xpc_connection_send_message(remote, reply);
+       xpc_release(reply);
+
+       if (target != NULL) CFRelease(target);
+       return;
+}
+
+
+static void
+target_status(reach_client_t *client, xpc_object_t request)
+{
+       xpc_connection_t                remote;
+       xpc_object_t                    reply;
+       __block Boolean                 reply_now       = TRUE;
+       Boolean                         scheduled;
+       uint64_t                        status          = REACH_REQUEST_REPLY_FAILED;
+       SCNetworkReachabilityRef        target          = NULL;
+       uint64_t                        target_id;
+
+       if(S_debug) {
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p> get status of reachability target"),
+                     client->connection);
+//             log_xpc_object("  status", request);
+       }
+
+       remote = xpc_dictionary_get_remote_connection(request);
+       reply = xpc_dictionary_create_reply(request);
+       if (reply == NULL) {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p> target_status: xpc_dictionary_create_reply: failed"),
+                     client->connection);
+               return;
+       }
+
+       target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID);
+       if (target_id == 0) {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p>   target_status: no target"),
+                     client->connection);
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target ID");
+               goto done;
+       }
+
+       target = _client_target_copy(client, target_id);
+       if (target == NULL) {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p>   target_status: no target (0x%0llx)"),
+                     client->connection,
+                     target_id);
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target");
+               status = REACH_REQUEST_REPLY_UNKNOWN;
+               goto done;
+       }
+
+       /*
+        * Check to see if the target [for this client] had been "scheduled".
+        *
+        * If so, also mark that we've picked up the current reachability
+        * flags and that any pending notifications have been processed.
+        */
+       scheduled = _target_watcher_checkin(target, client->connection, target_id);
+
+       /*
+        * return current reachability information to the caller
+        */
+       dispatch_sync(_target_queue(target), ^{
+               SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+               if (scheduled) {
+                       /*
+                        * The client "scheduled" this target.  As such, we
+                        * know that this an async query and that we only
+                        * need to return the "last known" flags.
+                        */
+                       _target_reply_add_reachability(target, reply);
+//                     log_xpc_object("  reply [scheduled]", reply);
+
+                       if (S_debug) {
+                               CFStringRef     str;
+
+                               str = _SCNetworkReachabilityCopyTargetFlags(target);
+                               SCLog(TRUE, LOG_INFO,
+                                     CFSTR("<%p>   reply [scheduled], %@"),
+                                     client->connection,
+                                     str);
+                               CFRelease(str);
+                       }
+               } else {
+                       /*
+                        * The client has NOT "scheduled" this target.  As
+                        * such, we know that this is a sync query and that
+                        * must return "current" flags.
+                        */
+                       if (targetPrivate->scheduled && targetPrivate->serverInfoValid) {
+                               /*
+                                * The server target has been "scheduled" and we
+                                * have flags that are "current".
+                                */
+                               _target_reply_add_reachability(target, reply);
+//                             log_xpc_object("  reply [scheduled/valid]", reply);
+
+                               if (S_debug) {
+                                       CFStringRef     str;
+
+                                       str = _SCNetworkReachabilityCopyTargetFlags(target);
+                                       SCLog(TRUE, LOG_INFO,
+                                             CFSTR("<%p>   reply [scheduled/valid], %@"),
+                                             client->connection,
+                                             str);
+                                       CFRelease(str);
+                               }
+                       } else {
+                               dispatch_group_t        group;
+
+                               /*
+                                * The server target has NOT been "scheduled" (or
+                                * we do not have "current" flags.  This means that
+                                * we must query for the current information and
+                                * return the flags to the client when they are
+                                * available.
+                                */
+
+                               reply_now = FALSE;
+
+                               group = _target_group(target);
+                               if (_SC_ATOMIC_INC(&targetPrivate->serverQueryActive) == 0) {
+                                       CFRetain(target);
+                                       dispatch_group_async(group, _server_concurrent_queue(), ^{
+                                               SCNetworkReachabilityFlags      flags;
+                                               unsigned int                    n;
+                                               Boolean                         ok;
+
+                                               // query for the flags
+                                               ok = SCNetworkReachabilityGetFlags(target, &flags);
+                                               flags = targetPrivate->info.flags;      // get the "raw" flags
+                                               if (!ok) {
+                                                       SCLog(TRUE, LOG_ERR,
+                                                             CFSTR("SCNetworkReachabilityGetFlags() [sync query] failed"
+                                                                   "\n  target = %@"
+                                                                   "\n  status = %s"),
+                                                             target,
+                                                             SCErrorString(SCError()));
+                                               }
+
+                                               // flags are now available
+                                               n = _SC_ATOMIC_ZERO(&targetPrivate->serverQueryActive);
+                                               if (S_debug) {
+                                                       SCLog(TRUE, LOG_INFO,
+                                                             CFSTR("%sSCNetworkReachabilityGetFlags() [sync query] complete, n = %d"),
+                                                             targetPrivate->log_prefix,
+                                                             n);
+                                               }
+
+                                               CFRelease(target);
+                                       });
+                               }
+
+                               CFRetain(target);
+                               dispatch_group_notify(group, _target_queue(target), ^{
+                                       // flags are now available
+                                       _target_reply_add_reachability(target, reply);
+                                       xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, REACH_REQUEST_REPLY_OK);
+//                                     log_xpc_object("  reply [delayed]", reply);
+
+                                       if (S_debug) {
+                                               CFStringRef     str;
+
+                                               str = _SCNetworkReachabilityCopyTargetFlags(target);
+                                               SCLog(TRUE, LOG_INFO,
+                                                     CFSTR("<%p>   reply [delayed], %@"),
+                                                     client->connection,
+                                                     str);
+                                               CFRelease(str);
+                                       }
+
+                                       xpc_connection_send_message(remote, reply);
+                                       xpc_release(reply);
+
+                                       CFRelease(target);
+                               });
+                       }
+               }
+       });
+
+       status = REACH_REQUEST_REPLY_OK;
+
+    done :
+
+       if (reply_now) {
+               xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status);
+
+               if (status != REACH_REQUEST_REPLY_OK) {
+//                     log_xpc_object("  reply [!]", reply);
+
+                       if (S_debug) {
+                               SCLog(TRUE, LOG_INFO,
+                                     CFSTR("<%p>   reply [!]"),
+                                     client->connection);
+                       }
+               }
+
+               xpc_connection_send_message(remote, reply);
+               xpc_release(reply);
+       } else if (S_debug) {
+               CFStringRef     str;
+
+               str = _SCNetworkReachabilityCopyTargetFlags(target);
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p>   no reply [yet], %@"),
+                     client->connection,
+                     str);
+               CFRelease(str);
+       }
+
+       if (target != NULL) CFRelease(target);
+       return;
+}
+
+
+static void
+target_unschedule(reach_client_t *client, xpc_object_t request)
+{
+       Boolean                         ok;
+       xpc_connection_t                remote;
+       xpc_object_t                    reply;
+       uint64_t                        status          = REACH_REQUEST_REPLY_FAILED;
+       SCNetworkReachabilityRef        target          = NULL;
+       uint64_t                        target_id;
+
+       if (S_debug) {
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p> unschedule reachability target"),
+                     client->connection);
+//             log_xpc_object("  unschedule", request);
+       }
+
+       remote = xpc_dictionary_get_remote_connection(request);
+       reply = xpc_dictionary_create_reply(request);
+       if (reply == NULL) {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p> target_unschedule: xpc_dictionary_create_reply: failed"),
+                     client->connection);
+               return;
+       }
+
+       target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID);
+       if (target_id == 0) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target ID");
+               goto done;
+       }
+
+       target = _client_target_copy(client, target_id);
+       if (target == NULL) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "no target");
+               status = REACH_REQUEST_REPLY_UNKNOWN;
+               goto done;
+       }
+
+       // disable monitoring
+       ok = _target_watcher_remove(target, client->connection, target_id);
+       if (ok) {
+               status = REACH_REQUEST_REPLY_OK;
+       }
+
+    done :
+
+       xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status);
+//     log_xpc_object("  reply", reply);
+       xpc_connection_send_message(remote, reply);
+       xpc_release(reply);
+
+       if (target != NULL) CFRelease(target);
+       return;
+}
+
+
+#define        SNAPSHOT_PATH_STATE     _PATH_VARTMP "configd-reachability"
+
+
+static void
+_snapshot_digest_watcher(const void *key, const void *value, void *context)
+{
+       FILE                            *f              = (FILE *)context;
+       static reach_client_t           no_client       = {
+               .pid = 0,
+               .proc_name = "?",
+       };
+       struct rb_node                  *rbn;
+       reach_client_t                  *rbt_client;
+       reach_watcher_key_t             *watcher_key;
+       reach_watcher_val_t             *watcher_val;
+
+       /* ALIGN: CF aligns to >8 byte boundries */
+       watcher_key = (reach_watcher_key_t *)(void *)CFDataGetBytePtr(key);
+       watcher_val = (reach_watcher_val_t *)(void *)CFDataGetBytePtr(value);
+
+       rbn = rb_tree_find_node(_reach_clients_rbt(), &watcher_key->connection);
+       if (rbn == NULL) {
+               rbn = &no_client.rbn;
+       }
+
+       rbt_client = RBNODE_TO_REACH_CLIENT(rbn);
+
+       SCPrint(TRUE, f,
+               CFSTR("      connection = %p, target(c) = 0x%0llx, command = %s, pid = %d, changes = %u\n"),
+               watcher_key->connection,
+               watcher_key->target_id,
+               rbt_client->proc_name,
+               rbt_client->pid,
+               watcher_val->n_changes);
+
+       return;
+}
+
+
+static void
+_snapshot_digest(const void *key, const void *value, void *context)
+{
+       FILE                            *f              = (FILE *)context;
+       CFStringRef                     digest          = (CFStringRef)key;
+       dispatch_queue_t                q;
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)value;
+       SCNetworkReachabilityPrivateRef targetPrivate   = (SCNetworkReachabilityPrivateRef)target;
+
+       q = _target_queue(target);
+       dispatch_sync(q, ^{
+               SCPrint(TRUE, f, CFSTR("\n  digest : %@\n"), digest);
+               SCPrint(TRUE, f, CFSTR("    %@\n"), target);
+               SCPrint(TRUE, f, CFSTR("    valid = %s, active = %u, refs = %u\n"),
+                       targetPrivate->serverInfoValid ? "Y" : "N",
+                       targetPrivate->serverQueryActive,
+                       targetPrivate->serverReferences);
+
+               SCPrint(TRUE, f, CFSTR("    network %d.%3.3d"),
+                       targetPrivate->last_network.tv_sec,
+                       targetPrivate->last_network.tv_usec / 1000);
+#if    !TARGET_OS_IPHONE
+               SCPrint(TRUE, f, CFSTR(", power %d.%3.3d"),
+                       targetPrivate->last_power.tv_sec,
+                       targetPrivate->last_power.tv_usec / 1000);
+#endif // !TARGET_OS_IPHONE
+               if (targetPrivate->type == reachabilityTypeName) {
+                       SCPrint(TRUE, f, CFSTR(", DNS %d.%3.3d"),
+                               targetPrivate->last_dns.tv_sec,
+                               targetPrivate->last_dns.tv_usec / 1000);
+                       if (timerisset(&targetPrivate->dnsQueryEnd)) {
+                               struct timeval  dnsQueryElapsed;
+
+                               timersub(&targetPrivate->dnsQueryEnd,
+                                        &targetPrivate->dnsQueryStart,
+                                        &dnsQueryElapsed);
+                               SCPrint(TRUE, f, CFSTR(" (query %d.%3.3d / reply %d.%3.3d)"),
+                                       targetPrivate->dnsQueryStart.tv_sec,
+                                       targetPrivate->dnsQueryStart.tv_usec / 1000,
+                                       dnsQueryElapsed.tv_sec,
+                                       dnsQueryElapsed.tv_usec / 1000);
+                       }
+               }
+               if (timerisset(&targetPrivate->last_push)) {
+                       SCPrint(TRUE, f, CFSTR(", last notify %d.%3.3d"),
+                               targetPrivate->last_push.tv_sec,
+                               targetPrivate->last_push.tv_usec / 1000);
+               }
+               SCPrint(TRUE, f, CFSTR("\n"));
+
+               if (targetPrivate->serverWatchers != NULL) {
+                       CFDictionaryApplyFunction(targetPrivate->serverWatchers,
+                                                 _snapshot_digest_watcher,
+                                                 f);
+               }
+       });
+
+       return;
+}
+
+
+static void
+_snapshot_target(const void *key, const void *value, void *context)
+{
+       FILE                            *f              = (FILE *)context;
+       SCNetworkReachabilityRef        target          = (SCNetworkReachabilityRef)value;
+       uint64_t                        target_id;
+       CFDataRef                       target_key      = (CFDataRef)key;
+
+       /* ALIGN: CF aligns > 8 byte boundries */
+       target_id = *(uint64_t *)(void *)CFDataGetBytePtr(target_key);
+
+       SCPrint(TRUE, f,
+               CFSTR("    target(c) = 0x%0llx, target(s) = %@\n"),
+               target_id,
+               target);
+
+       return;
+}
+
+
+static void
+_snapshot(reach_client_t *client, xpc_object_t request)
+{
+       uid_t                   euid;
+       FILE                    *f;
+       int                     fd;
+       Boolean                 ok      = FALSE;
+       struct rb_node          *rbn;
+       struct rb_tree          *rbt;
+       xpc_connection_t        remote;
+       xpc_object_t            reply;
+
+       if (S_debug) {
+               SCLog(TRUE, LOG_INFO,
+                     CFSTR("<%p> snapshot"),
+                     client->connection);
+//             log_xpc_object("  create", request);
+       }
+
+       remote = xpc_dictionary_get_remote_connection(request);
+       reply = xpc_dictionary_create_reply(request);
+       if (reply == NULL) {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("<%p> _snapshot: xpc_dictionary_create_reply: failed"),
+                     client->connection);
+               return;
+       }
+
+       euid = xpc_connection_get_euid(remote);
+       if (euid != 0) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "Permission denied.");
+               goto done;
+       }
+
+       // Save a snapshot of the SCNetworkReachability server "state"
+
+       (void) unlink(SNAPSHOT_PATH_STATE);
+       fd = open(SNAPSHOT_PATH_STATE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
+       if (fd == -1) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "open: failed");
+               goto done;
+       }
+       f = fdopen(fd, "w");
+       if (f == NULL) {
+               xpc_dictionary_set_string(reply,
+                                         REACH_REQUEST_REPLY_DETAIL,
+                                         "fdopen: failed");
+               goto done;
+       }
+
+       // provide connection/client info
+
+       SCPrint(TRUE, f, CFSTR("Clients :\n"));
+       rbt = _reach_clients_rbt();
+       rbn = rb_tree_iterate(rbt, NULL, RB_DIR_RIGHT);
+       if (rbn != NULL) {
+               while (rbn != NULL) {
+                       reach_client_t  *rbt_client;
+
+                       rbt_client = RBNODE_TO_REACH_CLIENT(rbn);
+                       SCPrint(TRUE, f,
+                               CFSTR("\n  connection = %p, client = %p, command = %s, pid = %d\n"),
+                               rbt_client->connection,
+                               rbt_client,
+                               rbt_client->proc_name != NULL ? rbt_client->proc_name : "?",
+                               rbt_client->pid);
+                       my_CFDictionaryApplyFunction(rbt_client->targets,
+                                                    _snapshot_target,
+                                                    f);
+
+                       rbn = rb_tree_iterate(rbt, rbn, RB_DIR_LEFT);
+               }
+       } else {
+               SCPrint(TRUE, f, CFSTR("  None.\n"));
+       }
+       SCPrint(TRUE, f, CFSTR("\n"));
+
+       // provide "digest" info
+
+       SCPrint(TRUE, f, CFSTR("Digests :\n"));
+       dispatch_sync(_server_digest_queue(), ^{
+               if (reach_digest_map != NULL) {
+                       CFDictionaryApplyFunction(reach_digest_map,
+                                                 _snapshot_digest,
+                                                 f);
+               }
+       });
+
+       (void) fclose(f);
+
+       ok = TRUE;
+
+    done :
+
+       xpc_dictionary_set_int64(reply,
+                                REACH_REQUEST_REPLY,
+                                ok ? REACH_REQUEST_REPLY_OK : REACH_REQUEST_REPLY_FAILED);
+//     log_xpc_object("  reply", reply);
+       xpc_connection_send_message(remote, reply);
+       xpc_release(reply);
+
+       return;
+}
+
+
+static __inline__ void
+_extract_client_info(reach_client_t *client, xpc_object_t request)
+{
+       // if available/needed, save the process name
+       if (client->proc_name == NULL) {
+               const char      *proc_name;
+
+               proc_name = xpc_dictionary_get_string(request, REACH_CLIENT_PROC_NAME);
+               if (proc_name != NULL) {
+                       client->proc_name = strdup(proc_name);
+               }
+       }
+
+       return;
+}
+
+
+static void
+process_request(reach_client_t *client, xpc_object_t request)
+{
+       int64_t         op;
+
+       op = xpc_dictionary_get_int64(request, REACH_REQUEST);
+       switch (op) {
+               case REACH_REQUEST_CREATE :
+                       _extract_client_info(client, request);
+                       target_add(client, request);
+                       break;
+               case REACH_REQUEST_REMOVE :
+                       target_remove(client, request);
+                       break;
+               case REACH_REQUEST_STATUS :
+                       target_status(client, request);
+                       break;
+               case REACH_REQUEST_SCHEDULE :
+                       target_schedule(client, request);
+                       break;
+               case REACH_REQUEST_UNSCHEDULE :
+                       target_unschedule(client, request);
+                       break;
+               case REACH_REQUEST_SNAPSHOT :
+                       _extract_client_info(client, request);
+                       _snapshot(client, request);
+                       break;
+               default :
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("<%p> unknown request : %d"),
+                             client->connection,
+                             op);
+                       break;
+       }
+
+       return;
+}
+
+
+static void
+process_new_connection(xpc_connection_t connection)
+{
+       if (S_debug) {
+               SCLog(TRUE, LOG_INFO, CFSTR("<%p> new reach client, pid=%d"),
+                     connection,
+                     xpc_connection_get_pid(connection));
+       }
+
+       dispatch_sync(_reach_connection_queue(), ^{
+               reach_client_t  *client;
+
+               client = _reach_client_create(connection);
+               if (client == NULL || !rb_tree_insert_node(_reach_clients_rbt(), &client->rbn)) {
+                       __builtin_trap();
+               }
+       });
+
+       xpc_connection_set_event_handler(connection, ^(xpc_object_t xobj) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(xobj);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       dispatch_sync(_reach_connection_queue(), ^{
+                               struct rb_node  *rbn;
+
+                               rbn = rb_tree_find_node(_reach_clients_rbt(), &connection);
+                               if (rbn != NULL) {
+                                       reach_client_t  *client;
+
+                                       // process the request
+                                       client = RBNODE_TO_REACH_CLIENT(rbn);
+                                       process_request(client, xobj);
+                               } else {
+                                       char            *desc;
+
+                                       SCLog(TRUE, LOG_ERR,
+                                             CFSTR("<%p:%d> unexpected SCNetworkReachability request"),
+                                             connection,
+                                             xpc_connection_get_pid(connection));
+
+                                       desc = xpc_copy_description(xobj);
+                                       SCLog(TRUE, LOG_ERR,
+                                             CFSTR("  request = %s"),
+                                             desc);
+                                       free(desc);
+
+                                       xpc_connection_cancel(connection);
+                               }
+                       });
+
+               } else if (type == XPC_TYPE_ERROR) {
+                       const char      *desc;
+
+                       desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION);
+                       if (xobj == XPC_ERROR_CONNECTION_INVALID) {
+                               if (S_debug) {
+                                       SCLog(TRUE, LOG_INFO,
+                                             CFSTR("<%p:%d> %s"),
+                                             connection,
+                                             xpc_connection_get_pid(connection),
+                                             desc);
+                               }
+
+                               xpc_retain(connection);
+                               dispatch_async(_reach_connection_queue(), ^{
+                                       _reach_client_remove(connection);
+                                       xpc_release(connection);
+                               });
+
+                       } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("<%p:%d> %s"),
+                                     connection,
+                                     xpc_connection_get_pid(connection),
+                                     desc);
+
+                       } else {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("<%p:%d> Connection error: %d : %s"),
+                                     connection,
+                                     xpc_connection_get_pid(connection),
+                                     xobj,
+                                     desc);
+                       }
+
+               }  else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("<%p:%d> unknown event type : %x"),
+                             connection,
+                             xpc_connection_get_pid(connection),
+                             type);
+               }
+       });
+
+       xpc_connection_resume(connection);
+
+       return;
+}
+
+
+#pragma mark -
+#pragma mark Reachability server "main"
+
+
+__private_extern__
+void
+load_SCNetworkReachability(CFBundleRef bundle, Boolean bundleVerbose)
+{
+       xpc_connection_t        connection;
+       const char              *name;
+       dispatch_queue_t        reach_server_q;
+
+       S_debug = bundleVerbose;
+
+       /*
+        * create a dictionary mapping SCNetworkReachability [CFData] digests
+        * to SCNetworkReachability objects.
+        */
+       reach_digest_map = CFDictionaryCreateMutable(NULL,
+                                                    0,
+                                                    &kCFTypeDictionaryKeyCallBacks,
+                                                    &kCFTypeDictionaryValueCallBacks);
+
+       /*
+        * create dispatch queue for processing SCNetworkReachability
+        * service requests
+        */
+       reach_server_q = dispatch_queue_create(REACH_SERVICE_NAME, NULL);
+
+       // create XPC listener
+       name = getenv("REACH_SERVER");
+       if (name == NULL) {
+               name = REACH_SERVICE_NAME;
+       }
+       connection = xpc_connection_create_mach_service(name,
+                                                       reach_server_q,
+                                                       XPC_CONNECTION_MACH_SERVICE_LISTENER);
+
+       xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
+               xpc_type_t      type;
+
+               type = xpc_get_type(event);
+               if (type == XPC_TYPE_CONNECTION) {
+                       process_new_connection(event);
+
+               } else if (type == XPC_TYPE_ERROR) {
+                       const char      *desc;
+
+                       desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
+                       if (event == XPC_ERROR_CONNECTION_INVALID) {
+                               SCLog(TRUE, LOG_ERR, CFSTR("reach server: %s"), desc);
+                               xpc_release(connection);
+                       } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
+                               SCLog(TRUE, LOG_ERR, CFSTR("reach server: %s"), desc);
+                       } else {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("reach server: Connection error: %d : %s"),
+                                     event,
+                                     desc);
+                       }
+
+               } else {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("reach server: unknown event type : %x"),
+                             type);
+               }
+       });
+       xpc_connection_resume(connection);
+
+       return;
+}
+
+#ifdef  MAIN
+
+int
+main(int argc, char **argv)
+{
+//     _sc_log     = FALSE;
+       _sc_verbose = (argc > 1) ? TRUE : FALSE;
+       _sc_debug   = TRUE;
+
+       load_SCNetworkReachability(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
+       CFRunLoopRun();
+       /* not reached */
+       exit(0);
+       return 0;
+}
+
+#endif  /* MAIN */
+
+#endif // HAVE_REACHABILITY_SERVER
diff --git a/SystemConfiguration.fproj/reachability/client.c b/SystemConfiguration.fproj/reachability/client.c
new file mode 100644 (file)
index 0000000..85279fb
--- /dev/null
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <SystemConfiguration/SCPrivate.h>
+
+#include "SCNetworkReachabilityInternal.h"
+
+int
+main(int argc, char **argv)
+{
+       Boolean                         ok;
+       SCNetworkReachabilityRef        target1;
+       SCNetworkReachabilityRef        target2;
+       SCNetworkReachabilityRef        target3;
+       SCNetworkReachabilityRef        target4;
+       SCNetworkReachabilityRef        target5;
+
+       _sc_log = FALSE;
+       _sc_debug = TRUE;       // extra reachability logging
+
+       target1 = SCNetworkReachabilityCreateWithName(NULL, "web.apple.com");
+       ok = __SCNetworkReachabilityServer_targetAdd(target1);
+       if (!ok) {
+               SCLog(TRUE, LOG_ERR, CFSTR("No reachability server"));
+               exit(1);
+       }
+
+       target2 = SCNetworkReachabilityCreateWithName(NULL, "www.comcast.net");
+       __SCNetworkReachabilityServer_targetAdd(target2);
+
+       target3 = SCNetworkReachabilityCreateWithName(NULL, "www.comcast.net");
+       __SCNetworkReachabilityServer_targetAdd(target3);
+
+       target4 = SCNetworkReachabilityCreateWithName(NULL, "www.nonexistenthost.com");
+       __SCNetworkReachabilityServer_targetAdd(target4);
+
+       target5 = SCNetworkReachabilityCreateWithName(NULL, "www.washingtonpost.com");
+       __SCNetworkReachabilityServer_targetAdd(target5);
+
+       __SCNetworkReachabilityServer_targetStatus(target1);
+       __SCNetworkReachabilityServer_targetStatus(target2);
+       __SCNetworkReachabilityServer_targetStatus(target3);
+       __SCNetworkReachabilityServer_targetStatus(target4);
+
+       __SCNetworkReachabilityServer_targetMonitor(target1, TRUE);
+       __SCNetworkReachabilityServer_targetMonitor(target4, TRUE);
+       __SCNetworkReachabilityServer_targetMonitor(target5, TRUE);
+
+       __SCNetworkReachabilityServer_targetStatus(target4);
+       __SCNetworkReachabilityServer_targetStatus(target3);
+       __SCNetworkReachabilityServer_targetStatus(target2);
+       __SCNetworkReachabilityServer_targetStatus(target1);
+
+       sleep(2);
+
+       __SCNetworkReachabilityServer_targetStatus(target1);
+       __SCNetworkReachabilityServer_targetStatus(target4);
+       __SCNetworkReachabilityServer_targetStatus(target1);
+       __SCNetworkReachabilityServer_targetStatus(target4);
+
+       __SCNetworkReachabilityServer_targetMonitor(target1, FALSE);
+
+       __SCNetworkReachabilityServer_targetStatus(target1);
+       __SCNetworkReachabilityServer_targetStatus(target4);
+       __SCNetworkReachabilityServer_targetStatus(target1);
+       __SCNetworkReachabilityServer_targetStatus(target4);
+
+       __SCNetworkReachabilityServer_targetMonitor(target4, FALSE);
+
+       __SCNetworkReachabilityServer_targetStatus(target1);
+       __SCNetworkReachabilityServer_targetStatus(target4);
+
+//     SCLog(TRUE, LOG_DEBUG, CFSTR("starting CFRunLoop"));
+//     CFRunLoopRun();
+//     SCLog(TRUE, LOG_DEBUG, CFSTR("CFRunLoop complete"));
+
+       SCLog(TRUE, LOG_DEBUG, CFSTR("sleeping"));
+       sleep(60);
+
+       __SCNetworkReachabilityServer_targetStatus(target5);
+       __SCNetworkReachabilityServer_targetRemove(target5);
+       CFRelease(target5);
+
+       __SCNetworkReachabilityServer_targetRemove(target4);
+       CFRelease(target4);
+
+       __SCNetworkReachabilityServer_targetRemove(target3);
+       CFRelease(target3);
+
+//     __SCNetworkReachabilityServer_targetRemove(target2);
+//     CFRelease(target2);
+
+//     __SCNetworkReachabilityServer_targetRemove(target1);
+//     CFRelease(target1);
+
+       exit(0);
+}
+
diff --git a/SystemConfiguration.fproj/reachability/rb.c b/SystemConfiguration.fproj/reachability/rb.c
new file mode 100644 (file)
index 0000000..21205db
--- /dev/null
@@ -0,0 +1,1323 @@
+/* $NetBSD: rb.c,v 1.4 2009/05/19 22:48:19 yamt Exp $ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas <matt@3am-software.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <sys/types.h>
+#include <stddef.h>
+#include <assert.h>
+#include <stdbool.h>
+#ifdef RBDEBUG
+#define        KASSERT(s)      assert(s)
+#else
+#define KASSERT(s)     do { } while (/*CONSTCOND*/ 0)
+#endif
+#else
+#include <lib/libkern/libkern.h>
+#endif
+
+#ifdef _LIBC
+__weak_alias(rb_tree_init, _rb_tree_init)
+__weak_alias(rb_tree_find_node, _rb_tree_find_node)
+__weak_alias(rb_tree_find_node_geq, _rb_tree_find_node_geq)
+__weak_alias(rb_tree_find_node_leq, _rb_tree_find_node_leq)
+__weak_alias(rb_tree_insert_node, _rb_tree_insert_node)
+__weak_alias(rb_tree_remove_node, _rb_tree_remove_node)
+__weak_alias(rb_tree_iterate, _rb_tree_iterate)
+#ifdef RBDEBUG
+__weak_alias(rb_tree_check, _rb_tree_check)
+__weak_alias(rb_tree_depths, _rb_tree_depths)
+#endif
+
+#define        rb_tree_init            _rb_tree_init
+#define        rb_tree_find_node       _rb_tree_find_node
+#define        rb_tree_find_node_geq   _rb_tree_find_node_geq
+#define        rb_tree_find_node_leq   _rb_tree_find_node_leq
+#define        rb_tree_insert_node     _rb_tree_insert_node
+#define        rb_tree_remove_node     _rb_tree_remove_node
+#define        rb_tree_iterate         _rb_tree_iterate
+#ifdef RBDEBUG
+#define        rb_tree_check           _rb_tree_check
+#define        rb_tree_depths          _rb_tree_depths
+#endif
+#endif
+
+#if defined(RBTEST) || defined(__APPLE__)
+#include "rb.h"
+#else
+#include <sys/rb.h>
+#endif
+
+#ifdef __APPLE__
+#define __predict_true(exp)     __builtin_expect((exp), 1)
+#define __predict_false(exp)    __builtin_expect((exp), 0)
+#endif
+
+static void rb_tree_insert_rebalance(struct rb_tree *, struct rb_node *);
+static void rb_tree_removal_rebalance(struct rb_tree *, struct rb_node *,
+       unsigned int);
+#ifdef RBDEBUG
+static const struct rb_node *rb_tree_iterate_const(const struct rb_tree *,
+       const struct rb_node *, const unsigned int);
+static bool rb_tree_check_node(const struct rb_tree *, const struct rb_node *,
+       const struct rb_node *, bool);
+#else
+#define        rb_tree_check_node(a, b, c, d)  true
+#endif
+
+#define        RB_SENTINEL_NODE        NULL
+
+void
+rb_tree_init(struct rb_tree *rbt, const struct rb_tree_ops *ops)
+{
+       rbt->rbt_ops = ops;
+       *((const struct rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE;
+       RB_TAILQ_INIT(&rbt->rbt_nodes);
+#ifndef RBSMALL
+       rbt->rbt_minmax[RB_DIR_LEFT] = rbt->rbt_root;   /* minimum node */
+       rbt->rbt_minmax[RB_DIR_RIGHT] = rbt->rbt_root;  /* maximum node */
+#endif
+       rbt->rbt_count = 0;
+#ifdef RBSTATS
+       rbt->rbt_insertions = 0;
+       rbt->rbt_removals = 0;
+       rbt->rbt_insertion_rebalance_calls = 0;
+       rbt->rbt_insertion_rebalance_passes = 0;
+       rbt->rbt_removal_rebalance_calls = 0;
+       rbt->rbt_removal_rebalance_passes = 0;
+#endif
+}
+
+struct rb_node *
+rb_tree_find_node(struct rb_tree *rbt, const void *key)
+{
+       rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
+       struct rb_node *parent = rbt->rbt_root;
+
+       while (!RB_SENTINEL_P(parent)) {
+               const signed int diff = (*compare_key)(parent, key);
+               if (diff == 0)
+                       return parent;
+               parent = parent->rb_nodes[diff > 0];
+       }
+
+       return NULL;
+}
+
+struct rb_node *
+rb_tree_find_node_geq(struct rb_tree *rbt, const void *key)
+{
+       rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
+       struct rb_node *parent = rbt->rbt_root;
+       struct rb_node *last = NULL;
+
+       while (!RB_SENTINEL_P(parent)) {
+               const signed int diff = (*compare_key)(parent, key);
+               if (diff == 0)
+                       return parent;
+               if (diff < 0)
+                       last = parent;
+               parent = parent->rb_nodes[diff > 0];
+       }
+
+       return last;
+}
+
+struct rb_node *
+rb_tree_find_node_leq(struct rb_tree *rbt, const void *key)
+{
+       rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
+       struct rb_node *parent = rbt->rbt_root;
+       struct rb_node *last = NULL;
+
+       while (!RB_SENTINEL_P(parent)) {
+               const signed int diff = (*compare_key)(parent, key);
+               if (diff == 0)
+                       return parent;
+               if (diff > 0)
+                       last = parent;
+               parent = parent->rb_nodes[diff > 0];
+       }
+
+       return last;
+}
+\f
+bool
+rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
+{
+       rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes;
+       struct rb_node *parent, *tmp;
+       unsigned int position;
+       bool rebalance;
+
+       RBSTAT_INC(rbt->rbt_insertions);
+
+       tmp = rbt->rbt_root;
+       /*
+        * This is a hack.  Because rbt->rbt_root is just a struct rb_node *,
+        * just like rb_node->rb_nodes[RB_DIR_LEFT], we can use this fact to
+        * avoid a lot of tests for root and know that even at root,
+        * updating RB_FATHER(rb_node)->rb_nodes[RB_POSITION(rb_node)] will
+        * update rbt->rbt_root.
+        */
+       parent = (struct rb_node *)(void *)&rbt->rbt_root;
+       position = RB_DIR_LEFT;
+
+       /*
+        * Find out where to place this new leaf.
+        */
+       while (!RB_SENTINEL_P(tmp)) {
+               const signed int diff = (*compare_nodes)(tmp, self);
+               if (__predict_false(diff == 0)) {
+                       /*
+                        * Node already exists; don't insert.
+                        */
+                       return false;
+               }
+               parent = tmp;
+               position = (diff > 0);
+               tmp = parent->rb_nodes[position];
+       }
+
+#ifdef RBDEBUG
+       {
+               struct rb_node *prev = NULL, *next = NULL;
+
+               if (position == RB_DIR_RIGHT)
+                       prev = parent;
+               else if (tmp != rbt->rbt_root)
+                       next = parent;
+
+               /*
+                * Verify our sequential position
+                */
+               KASSERT(prev == NULL || !RB_SENTINEL_P(prev));
+               KASSERT(next == NULL || !RB_SENTINEL_P(next));
+               if (prev != NULL && next == NULL)
+                       next = TAILQ_NEXT(prev, rb_link);
+               if (prev == NULL && next != NULL)
+                       prev = TAILQ_PREV(next, rb_node_qh, rb_link);
+               KASSERT(prev == NULL || !RB_SENTINEL_P(prev));
+               KASSERT(next == NULL || !RB_SENTINEL_P(next));
+               KASSERT(prev == NULL || (*compare_nodes)(prev, self) > 0);
+               KASSERT(next == NULL || (*compare_nodes)(self, next) > 0);
+       }
+#endif
+
+       /*
+        * Initialize the node and insert as a leaf into the tree.
+        */
+       RB_SET_FATHER(self, parent);
+       RB_SET_POSITION(self, position);
+       if (__predict_false(parent == (struct rb_node *)(void *)&rbt->rbt_root)) {
+               RB_MARK_BLACK(self);            /* root is always black */
+#ifndef RBSMALL
+               rbt->rbt_minmax[RB_DIR_LEFT] = self;
+               rbt->rbt_minmax[RB_DIR_RIGHT] = self;
+#endif
+               rebalance = false;
+       } else {
+               KASSERT(position == RB_DIR_LEFT || position == RB_DIR_RIGHT);
+#ifndef RBSMALL
+               /*
+                * Keep track of the minimum and maximum nodes.  If our
+                * parent is a minmax node and we on their min/max side,
+                * we must be the new min/max node.
+                */
+               if (parent == rbt->rbt_minmax[position])
+                       rbt->rbt_minmax[position] = self;
+#endif /* !RBSMALL */
+               /*
+                * All new nodes are colored red.  We only need to rebalance
+                * if our parent is also red.
+                */
+               RB_MARK_RED(self);
+               rebalance = RB_RED_P(parent);
+       }
+       KASSERT(RB_SENTINEL_P(parent->rb_nodes[position]));
+       self->rb_left = parent->rb_nodes[position];
+       self->rb_right = parent->rb_nodes[position];
+       parent->rb_nodes[position] = self;
+       KASSERT(RB_CHILDLESS_P(self));
+
+       /*
+        * Insert the new node into a sorted list for easy sequential access
+        */
+       rbt->rbt_count++;
+#ifdef RBDEBUG
+       if (RB_ROOT_P(rbt, self)) {
+               RB_TAILQ_INSERT_HEAD(&rbt->rbt_nodes, self, rb_link);
+       } else if (position == RB_DIR_LEFT) {
+               KASSERT((*compare_nodes)(self, RB_FATHER(self)) > 0);
+               RB_TAILQ_INSERT_BEFORE(RB_FATHER(self), self, rb_link);
+       } else {
+               KASSERT((*compare_nodes)(RB_FATHER(self), self) > 0);
+               RB_TAILQ_INSERT_AFTER(&rbt->rbt_nodes, RB_FATHER(self),
+                   self, rb_link);
+       }
+#endif
+       KASSERT(rb_tree_check_node(rbt, self, NULL, !rebalance));
+
+       /*
+        * Rebalance tree after insertion
+        */
+       if (rebalance) {
+               rb_tree_insert_rebalance(rbt, self);
+               KASSERT(rb_tree_check_node(rbt, self, NULL, true));
+       }
+
+       return true;
+}
+\f
+/*
+ * Swap the location and colors of 'self' and its child @ which.  The child
+ * can not be a sentinel node.  This is our rotation function.  However,
+ * since it preserves coloring, it great simplifies both insertion and
+ * removal since rotation almost always involves the exchanging of colors
+ * as a separate step.
+ */
+/*ARGSUSED*/
+static void
+rb_tree_reparent_nodes(struct rb_tree *rbt, struct rb_node *old_father,
+       const unsigned int which)
+{
+       const unsigned int other = which ^ RB_DIR_OTHER;
+       struct rb_node * const grandpa = RB_FATHER(old_father);
+       struct rb_node * const old_child = old_father->rb_nodes[which];
+       struct rb_node * const new_father = old_child;
+       struct rb_node * const new_child = old_father;
+
+       KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT);
+
+       KASSERT(!RB_SENTINEL_P(old_child));
+       KASSERT(RB_FATHER(old_child) == old_father);
+
+       KASSERT(rb_tree_check_node(rbt, old_father, NULL, false));
+       KASSERT(rb_tree_check_node(rbt, old_child, NULL, false));
+       KASSERT(RB_ROOT_P(rbt, old_father) || rb_tree_check_node(rbt, grandpa, NULL, false));
+
+       /*
+        * Exchange descendant linkages.
+        */
+       grandpa->rb_nodes[RB_POSITION(old_father)] = new_father;
+       new_child->rb_nodes[which] = old_child->rb_nodes[other];
+       new_father->rb_nodes[other] = new_child;
+
+       /*
+        * Update ancestor linkages
+        */
+       RB_SET_FATHER(new_father, grandpa);
+       RB_SET_FATHER(new_child, new_father);
+
+       /*
+        * Exchange properties between new_father and new_child.  The only
+        * change is that new_child's position is now on the other side.
+        */
+#if 0
+       {
+               struct rb_node tmp;
+               tmp.rb_info = 0;
+               RB_COPY_PROPERTIES(&tmp, old_child);
+               RB_COPY_PROPERTIES(new_father, old_father);
+               RB_COPY_PROPERTIES(new_child, &tmp);
+       }
+#else
+       RB_SWAP_PROPERTIES(new_father, new_child);
+#endif
+       RB_SET_POSITION(new_child, other);
+
+       /*
+        * Make sure to reparent the new child to ourself.
+        */
+       if (!RB_SENTINEL_P(new_child->rb_nodes[which])) {
+               RB_SET_FATHER(new_child->rb_nodes[which], new_child);
+               RB_SET_POSITION(new_child->rb_nodes[which], which);
+       }
+
+       KASSERT(rb_tree_check_node(rbt, new_father, NULL, false));
+       KASSERT(rb_tree_check_node(rbt, new_child, NULL, false));
+       KASSERT(RB_ROOT_P(rbt, new_father) || rb_tree_check_node(rbt, grandpa, NULL, false));
+}
+\f
+static void
+rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self)
+{
+       struct rb_node * father = RB_FATHER(self);
+       struct rb_node * grandpa;
+       struct rb_node * uncle;
+       unsigned int which;
+       unsigned int other;
+
+       KASSERT(!RB_ROOT_P(rbt, self));
+       KASSERT(RB_RED_P(self));
+       KASSERT(RB_RED_P(father));
+       RBSTAT_INC(rbt->rbt_insertion_rebalance_calls);
+
+       for (;;) {
+               KASSERT(!RB_SENTINEL_P(self));
+
+               KASSERT(RB_RED_P(self));
+               KASSERT(RB_RED_P(father));
+               /*
+                * We are red and our parent is red, therefore we must have a
+                * grandfather and he must be black.
+                */
+               grandpa = RB_FATHER(father);
+               KASSERT(RB_BLACK_P(grandpa));
+               KASSERT(RB_DIR_RIGHT == 1 && RB_DIR_LEFT == 0);
+               which = (father == grandpa->rb_right);
+               other = which ^ RB_DIR_OTHER;
+               uncle = grandpa->rb_nodes[other];
+
+               if (RB_BLACK_P(uncle))
+                       break;
+
+               RBSTAT_INC(rbt->rbt_insertion_rebalance_passes);
+               /*
+                * Case 1: our uncle is red
+                *   Simply invert the colors of our parent and
+                *   uncle and make our grandparent red.  And
+                *   then solve the problem up at his level.
+                */
+               RB_MARK_BLACK(uncle);
+               RB_MARK_BLACK(father);
+               if (__predict_false(RB_ROOT_P(rbt, grandpa))) {
+                       /*
+                        * If our grandpa is root, don't bother
+                        * setting him to red, just return.
+                        */
+                       KASSERT(RB_BLACK_P(grandpa));
+                       return;
+               }
+               RB_MARK_RED(grandpa);
+               self = grandpa;
+               father = RB_FATHER(self);
+               KASSERT(RB_RED_P(self));
+               if (RB_BLACK_P(father)) {
+                       /*
+                        * If our greatgrandpa is black, we're done.
+                        */
+                       KASSERT(RB_BLACK_P(rbt->rbt_root));
+                       return;
+               }
+       }
+
+       KASSERT(!RB_ROOT_P(rbt, self));
+       KASSERT(RB_RED_P(self));
+       KASSERT(RB_RED_P(father));
+       KASSERT(RB_BLACK_P(uncle));
+       KASSERT(RB_BLACK_P(grandpa));
+       /*
+        * Case 2&3: our uncle is black.
+        */
+       if (self == father->rb_nodes[other]) {
+               /*
+                * Case 2: we are on the same side as our uncle
+                *   Swap ourselves with our parent so this case
+                *   becomes case 3.  Basically our parent becomes our
+                *   child.
+                */
+               rb_tree_reparent_nodes(rbt, father, other);
+               KASSERT(RB_FATHER(father) == self);
+               KASSERT(self->rb_nodes[which] == father);
+               KASSERT(RB_FATHER(self) == grandpa);
+#ifdef RBDEBUG
+               // only read when RBDEBUG is enabled with KASSERT
+               self = father;
+               father = RB_FATHER(self);
+#endif
+       }
+       KASSERT(RB_RED_P(self) && RB_RED_P(father));
+       KASSERT(grandpa->rb_nodes[which] == father);
+       /*
+        * Case 3: we are opposite a child of a black uncle.
+        *   Swap our parent and grandparent.  Since our grandfather
+        *   is black, our father will become black and our new sibling
+        *   (former grandparent) will become red.
+        */
+       rb_tree_reparent_nodes(rbt, grandpa, which);
+       KASSERT(RB_FATHER(self) == father);
+       KASSERT(RB_FATHER(self)->rb_nodes[RB_POSITION(self) ^ RB_DIR_OTHER] == grandpa);
+       KASSERT(RB_RED_P(self));
+       KASSERT(RB_BLACK_P(father));
+       KASSERT(RB_RED_P(grandpa));
+
+       /*
+        * Final step: Set the root to black.
+        */
+       RB_MARK_BLACK(rbt->rbt_root);
+}
+\f
+static void
+rb_tree_prune_node(struct rb_tree *rbt, struct rb_node *self, bool rebalance)
+{
+       const unsigned int which = RB_POSITION(self);
+       struct rb_node *father = RB_FATHER(self);
+       const bool was_root = RB_ROOT_P(rbt, self);
+
+       KASSERT(rebalance || (RB_ROOT_P(rbt, self) || RB_RED_P(self)));
+       KASSERT(!rebalance || RB_BLACK_P(self));
+       KASSERT(RB_CHILDLESS_P(self));
+       KASSERT(rb_tree_check_node(rbt, self, NULL, false));
+
+       /*
+        * Since we are childless, we know that self->rb_left is pointing
+        * to the sentinel node.
+        */
+       father->rb_nodes[which] = self->rb_left;
+
+       /*
+        * Remove ourselves from the node list, decrement the count,
+        * and update min/max.
+        */
+       RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
+       rbt->rbt_count--;
+#ifndef RBSMALL
+       if (__predict_false(rbt->rbt_minmax[RB_POSITION(self)] == self)) {
+               rbt->rbt_minmax[RB_POSITION(self)] = father;
+               /*
+                * When removing the root, rbt->rbt_minmax[RB_DIR_LEFT] is
+                * updated automatically, but we also need to update
+                * rbt->rbt_minmax[RB_DIR_RIGHT];
+                */
+               if (__predict_false(was_root)) {
+                       rbt->rbt_minmax[RB_DIR_RIGHT] = father;
+               }
+       }
+       RB_SET_FATHER(self, NULL);
+#endif
+
+       /*
+        * Rebalance if requested.
+        */
+       if (rebalance)
+               rb_tree_removal_rebalance(rbt, father, which);
+       KASSERT(was_root || rb_tree_check_node(rbt, father, NULL, true));
+}
+\f
+/*
+ * When deleting an interior node
+ */
+static void
+rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self,
+       struct rb_node *standin)
+{
+       const unsigned int standin_which = RB_POSITION(standin);
+       unsigned int standin_other = standin_which ^ RB_DIR_OTHER;
+       struct rb_node *standin_son;
+       struct rb_node *standin_father = RB_FATHER(standin);
+       bool rebalance = RB_BLACK_P(standin);
+
+       if (standin_father == self) {
+               /*
+                * As a child of self, any childen would be opposite of
+                * our parent.
+                */
+               KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other]));
+               standin_son = standin->rb_nodes[standin_which];
+       } else {
+               /*
+                * Since we aren't a child of self, any childen would be
+                * on the same side as our parent.
+                */
+               KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_which]));
+               standin_son = standin->rb_nodes[standin_other];
+       }
+
+       /*
+        * the node we are removing must have two children.
+        */
+       KASSERT(RB_TWOCHILDREN_P(self));
+       /*
+        * If standin has a child, it must be red.
+        */
+       KASSERT(RB_SENTINEL_P(standin_son) || RB_RED_P(standin_son));
+
+       /*
+        * Verify things are sane.
+        */
+       KASSERT(rb_tree_check_node(rbt, self, NULL, false));
+       KASSERT(rb_tree_check_node(rbt, standin, NULL, false));
+
+       if (__predict_false(RB_RED_P(standin_son))) {
+               /*
+                * We know we have a red child so if we flip it to black
+                * we don't have to rebalance.
+                */
+               KASSERT(rb_tree_check_node(rbt, standin_son, NULL, true));
+               RB_MARK_BLACK(standin_son);
+               rebalance = false;
+
+               if (standin_father == self) {
+                       KASSERT(RB_POSITION(standin_son) == standin_which);
+               } else {
+                       KASSERT(RB_POSITION(standin_son) == standin_other);
+                       /*
+                        * Change the son's parentage to point to his grandpa.
+                        */
+                       RB_SET_FATHER(standin_son, standin_father);
+                       RB_SET_POSITION(standin_son, standin_which);
+               }
+       }
+
+       if (standin_father == self) {
+               /*
+                * If we are about to delete the standin's father, then when
+                * we call rebalance, we need to use ourselves as our father.
+                * Otherwise remember our original father.  Also, sincef we are
+                * our standin's father we only need to reparent the standin's
+                * brother.
+                *
+                * |    R      -->     S    |
+                * |  Q   S    -->   Q   T  |
+                * |        t  -->          |
+                */
+               KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other]));
+               KASSERT(!RB_SENTINEL_P(self->rb_nodes[standin_other]));
+               KASSERT(self->rb_nodes[standin_which] == standin);
+               /*
+                * Have our son/standin adopt his brother as his new son.
+                */
+               standin_father = standin;
+       } else {
+               /*
+                * |    R          -->    S       .  |
+                * |   / \  |   T  -->   / \  |  /   |
+                * |  ..... | S    -->  ..... | T    |
+                *
+                * Sever standin's connection to his father.
+                */
+               standin_father->rb_nodes[standin_which] = standin_son;
+               /*
+                * Adopt the far son.
+                */
+               standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];
+               RB_SET_FATHER(standin->rb_nodes[standin_other], standin);
+               KASSERT(RB_POSITION(self->rb_nodes[standin_other]) == standin_other);
+               /*
+                * Use standin_other because we need to preserve standin_which
+                * for the removal_rebalance.
+                */
+               standin_other = standin_which;
+       }
+
+       /*
+        * Move the only remaining son to our standin.  If our standin is our
+        * son, this will be the only son needed to be moved.
+        */
+       KASSERT(standin->rb_nodes[standin_other] != self->rb_nodes[standin_other]);
+       standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];
+       RB_SET_FATHER(standin->rb_nodes[standin_other], standin);
+
+       /*
+        * Now copy the result of self to standin and then replace
+        * self with standin in the tree.
+        */
+       RB_COPY_PROPERTIES(standin, self);
+       RB_SET_FATHER(standin, RB_FATHER(self));
+       RB_FATHER(standin)->rb_nodes[RB_POSITION(standin)] = standin;
+
+       /*
+        * Remove ourselves from the node list, decrement the count,
+        * and update min/max.
+        */
+       RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
+       rbt->rbt_count--;
+#ifndef RBSMALL
+       if (__predict_false(rbt->rbt_minmax[RB_POSITION(self)] == self))
+               rbt->rbt_minmax[RB_POSITION(self)] = RB_FATHER(self);
+       RB_SET_FATHER(self, NULL);
+#endif
+
+       KASSERT(rb_tree_check_node(rbt, standin, NULL, false));
+       KASSERT(RB_FATHER_SENTINEL_P(standin)
+               || rb_tree_check_node(rbt, standin_father, NULL, false));
+       KASSERT(RB_LEFT_SENTINEL_P(standin)
+               || rb_tree_check_node(rbt, standin->rb_left, NULL, false));
+       KASSERT(RB_RIGHT_SENTINEL_P(standin)
+               || rb_tree_check_node(rbt, standin->rb_right, NULL, false));
+
+       if (!rebalance)
+               return;
+
+       rb_tree_removal_rebalance(rbt, standin_father, standin_which);
+       KASSERT(rb_tree_check_node(rbt, standin, NULL, true));
+}
+
+/*
+ * We could do this by doing
+ *     rb_tree_node_swap(rbt, self, which);
+ *     rb_tree_prune_node(rbt, self, false);
+ *
+ * But it's more efficient to just evalate and recolor the child.
+ */
+static void
+rb_tree_prune_blackred_branch(struct rb_tree *rbt, struct rb_node *self,
+       unsigned int which)
+{
+       struct rb_node *father = RB_FATHER(self);
+       struct rb_node *son = self->rb_nodes[which];
+       const bool was_root = RB_ROOT_P(rbt, self);
+
+       KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT);
+       KASSERT(RB_BLACK_P(self) && RB_RED_P(son));
+       KASSERT(!RB_TWOCHILDREN_P(son));
+       KASSERT(RB_CHILDLESS_P(son));
+       KASSERT(rb_tree_check_node(rbt, self, NULL, false));
+       KASSERT(rb_tree_check_node(rbt, son, NULL, false));
+
+       /*
+        * Remove ourselves from the tree and give our former child our
+        * properties (position, color, root).
+        */
+       RB_COPY_PROPERTIES(son, self);
+       father->rb_nodes[RB_POSITION(son)] = son;
+       RB_SET_FATHER(son, father);
+
+       /*
+        * Remove ourselves from the node list, decrement the count,
+        * and update minmax.
+        */
+       RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
+       rbt->rbt_count--;
+#ifndef RBSMALL
+       if (__predict_false(was_root)) {
+               KASSERT(rbt->rbt_minmax[which] == son);
+               rbt->rbt_minmax[which ^ RB_DIR_OTHER] = son;
+       } else if (rbt->rbt_minmax[RB_POSITION(self)] == self) {
+               rbt->rbt_minmax[RB_POSITION(self)] = son;
+       }
+       RB_SET_FATHER(self, NULL);
+#endif
+
+       KASSERT(was_root || rb_tree_check_node(rbt, father, NULL, true));
+       KASSERT(rb_tree_check_node(rbt, son, NULL, true));
+}
+/*
+ *
+ */
+void
+rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self)
+{
+       struct rb_node *standin;
+       unsigned int which;
+
+       KASSERT(!RB_SENTINEL_P(self));
+       RBSTAT_INC(rbt->rbt_removals);
+
+       /*
+        * In the following diagrams, we (the node to be removed) are S.  Red
+        * nodes are lowercase.  T could be either red or black.
+        *
+        * Remember the major axiom of the red-black tree: the number of
+        * black nodes from the root to each leaf is constant across all
+        * leaves, only the number of red nodes varies.
+        *
+        * Thus removing a red leaf doesn't require any other changes to a
+        * red-black tree.  So if we must remove a node, attempt to rearrange
+        * the tree so we can remove a red node.
+        *
+        * The simpliest case is a childless red node or a childless root node:
+        *
+        * |    T  -->    T  |    or    |  R  -->  *  |
+        * |  s    -->  *    |
+        */
+       if (RB_CHILDLESS_P(self)) {
+               const bool rebalance = RB_BLACK_P(self) && !RB_ROOT_P(rbt, self);
+               rb_tree_prune_node(rbt, self, rebalance);
+               return;
+       }
+       KASSERT(!RB_CHILDLESS_P(self));
+       if (!RB_TWOCHILDREN_P(self)) {
+               /*
+                * The next simpliest case is the node we are deleting is
+                * black and has one red child.
+                *
+                * |      T  -->      T  -->      T  |
+                * |    S    -->  R      -->  R      |
+                * |  r      -->    s    -->    *    |
+                */
+               which = RB_LEFT_SENTINEL_P(self) ? RB_DIR_RIGHT : RB_DIR_LEFT;
+               KASSERT(RB_BLACK_P(self));
+               KASSERT(RB_RED_P(self->rb_nodes[which]));
+               KASSERT(RB_CHILDLESS_P(self->rb_nodes[which]));
+               rb_tree_prune_blackred_branch(rbt, self, which);
+               return;
+       }
+       KASSERT(RB_TWOCHILDREN_P(self));
+
+       /*
+        * We invert these because we prefer to remove from the inside of
+        * the tree.
+        */
+       which = RB_POSITION(self) ^ RB_DIR_OTHER;
+
+       /*
+        * Let's find the node closes to us opposite of our parent
+        * Now swap it with ourself, "prune" it, and rebalance, if needed.
+        */
+       standin = rb_tree_iterate(rbt, self, which);
+       rb_tree_swap_prune_and_rebalance(rbt, self, standin);
+}
+
+static void
+rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
+       unsigned int which)
+{
+       KASSERT(!RB_SENTINEL_P(parent));
+       KASSERT(RB_SENTINEL_P(parent->rb_nodes[which]));
+       KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT);
+       RBSTAT_INC(rbt->rbt_removal_rebalance_calls);
+
+       while (RB_BLACK_P(parent->rb_nodes[which])) {
+               unsigned int other = which ^ RB_DIR_OTHER;
+               struct rb_node *brother = parent->rb_nodes[other];
+
+               RBSTAT_INC(rbt->rbt_removal_rebalance_passes);
+
+               KASSERT(!RB_SENTINEL_P(brother));
+               /*
+                * For cases 1, 2a, and 2b, our brother's children must
+                * be black and our father must be black
+                */
+               if (RB_BLACK_P(parent)
+                   && RB_BLACK_P(brother->rb_left)
+                   && RB_BLACK_P(brother->rb_right)) {
+                       if (RB_RED_P(brother)) {
+                               /*
+                                * Case 1: Our brother is red, swap its
+                                * position (and colors) with our parent.
+                                * This should now be case 2b (unless C or E
+                                * has a red child which is case 3; thus no
+                                * explicit branch to case 2b).
+                                *
+                                *    B         ->        D
+                                *  A     d     ->    b     E
+                                *      C   E   ->  A   C
+                                */
+                               KASSERT(RB_BLACK_P(parent));
+                               rb_tree_reparent_nodes(rbt, parent, other);
+                               brother = parent->rb_nodes[other];
+                               KASSERT(!RB_SENTINEL_P(brother));
+                               KASSERT(RB_RED_P(parent));
+                               KASSERT(RB_BLACK_P(brother));
+                               KASSERT(rb_tree_check_node(rbt, brother, NULL, false));
+                               KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
+                       } else {
+                               /*
+                                * Both our parent and brother are black.
+                                * Change our brother to red, advance up rank
+                                * and go through the loop again.
+                                *
+                                *    B         ->   *B
+                                * *A     D     ->  A     d
+                                *      C   E   ->      C   E
+                                */
+                               RB_MARK_RED(brother);
+                               KASSERT(RB_BLACK_P(brother->rb_left));
+                               KASSERT(RB_BLACK_P(brother->rb_right));
+                               if (RB_ROOT_P(rbt, parent))
+                                       return; /* root == parent == black */
+                               KASSERT(rb_tree_check_node(rbt, brother, NULL, false));
+                               KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
+                               if (parent != NULL) {
+                                       which = RB_POSITION(parent);
+                                       parent = RB_FATHER(parent);
+                               }
+                               continue;
+                       }
+               }
+               /*
+                * Avoid an else here so that case 2a above can hit either
+                * case 2b, 3, or 4.
+                */
+               if (RB_RED_P(parent)
+                       && (RB_SENTINEL_P(brother)
+                               || (RB_BLACK_P(brother)
+                                       && RB_BLACK_P(brother->rb_left)
+                                       && RB_BLACK_P(brother->rb_right)))) {
+                       KASSERT(RB_RED_P(parent));
+                       KASSERT(RB_BLACK_P(brother));
+                       KASSERT(RB_BLACK_P(brother->rb_left));
+                       KASSERT(RB_BLACK_P(brother->rb_right));
+                       /*
+                        * We are black, our father is red, our brother and
+                        * both nephews are black.  Simply invert/exchange the
+                        * colors of our father and brother (to black and red
+                        * respectively).
+                        *
+                        *      |    f        -->    F        |
+                        *      |  *     B    -->  *     b    |
+                        *      |      N   N  -->      N   N  |
+                        */
+                       RB_MARK_BLACK(parent);
+                       if (!RB_SENTINEL_P(brother)) {
+                               RB_MARK_RED(brother);
+                       }
+                       KASSERT(rb_tree_check_node(rbt, brother, NULL, true));
+                       break;          /* We're done! */
+               } else {
+                       /*
+                        * Our brother must be black and have at least one
+                        * red child (it may have two).
+                        */
+                       KASSERT(RB_BLACK_P(brother));
+                       KASSERT(RB_RED_P(brother->rb_nodes[which]) ||
+                               RB_RED_P(brother->rb_nodes[other]));
+                       if (RB_BLACK_P(brother->rb_nodes[other])) {
+                               /*
+                                * Case 3: our brother is black, our near
+                                * nephew is red, and our far nephew is black.
+                                * Swap our brother with our near nephew.
+                                * This result in a tree that matches case 4.
+                                * (Our father could be red or black).
+                                *
+                                *      |    F      -->    F      |
+                                *      |  x     B  -->  x   B    |
+                                *      |      n    -->        n  |
+                                */
+                               KASSERT(RB_RED_P(brother->rb_nodes[which]));
+                               rb_tree_reparent_nodes(rbt, brother, which);
+                               KASSERT(RB_FATHER(brother) == parent->rb_nodes[other]);
+                               brother = parent->rb_nodes[other];
+                               KASSERT(RB_RED_P(brother->rb_nodes[other]));
+                       }
+                       /*
+                        * Case 4: our brother is black and our far nephew
+                        * is red.  Swap our father and brother locations and
+                        * change our far nephew to black.  (these can be
+                        * done in either order so we change the color first).
+                        * The result is a valid red-black tree and is a
+                        * terminal case.  (again we don't care about the
+                        * father's color)
+                        *
+                        * If the father is red, we will get a red-black-black
+                        * tree:
+                        *      |  f      ->  f      -->    b    |
+                        *      |    B    ->    B    -->  F   N  |
+                        *      |      n  ->      N  -->         |
+                        *
+                        * If the father is black, we will get an all black
+                        * tree:
+                        *      |  F      ->  F      -->    B    |
+                        *      |    B    ->    B    -->  F   N  |
+                        *      |      n  ->      N  -->         |
+                        *
+                        * If we had two red nephews, then after the swap,
+                        * our former father would have a red grandson.
+                        */
+                       KASSERT(RB_BLACK_P(brother));
+                       KASSERT(RB_RED_P(brother->rb_nodes[other]));
+                       RB_MARK_BLACK(brother->rb_nodes[other]);
+                       rb_tree_reparent_nodes(rbt, parent, other);
+                       break;          /* We're done! */
+               }
+       }
+       KASSERT(rb_tree_check_node(rbt, parent, NULL, true));
+}
+
+struct rb_node *
+rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self,
+       const unsigned int direction)
+{
+       const unsigned int other = direction ^ RB_DIR_OTHER;
+       KASSERT(direction == RB_DIR_LEFT || direction == RB_DIR_RIGHT);
+
+       if (self == NULL) {
+#ifndef RBSMALL
+               if (RB_SENTINEL_P(rbt->rbt_root))
+                       return NULL;
+               return rbt->rbt_minmax[direction];
+#else
+               self = rbt->rbt_root;
+               if (RB_SENTINEL_P(self))
+                       return NULL;
+               while (!RB_SENTINEL_P(self->rb_nodes[other]))
+                       self = self->rb_nodes[other];
+               return self;
+#endif /* !RBSMALL */
+       }
+       KASSERT(!RB_SENTINEL_P(self));
+       /*
+        * We can't go any further in this direction.  We proceed up in the
+        * opposite direction until our parent is in direction we want to go.
+        */
+       if (RB_SENTINEL_P(self->rb_nodes[direction])) {
+               while (!RB_ROOT_P(rbt, self)) {
+                       if (other == RB_POSITION(self))
+                               return RB_FATHER(self);
+                       self = RB_FATHER(self);
+               }
+               return NULL;
+       }
+
+       /*
+        * Advance down one in current direction and go down as far as possible
+        * in the opposite direction.
+        */
+       self = self->rb_nodes[direction];
+       KASSERT(!RB_SENTINEL_P(self));
+       while (!RB_SENTINEL_P(self->rb_nodes[other]))
+               self = self->rb_nodes[other];
+       return self;
+}
+
+#ifdef RBDEBUG
+static const struct rb_node *
+rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self,
+       const unsigned int direction)
+{
+       const unsigned int other = direction ^ RB_DIR_OTHER;
+       KASSERT(direction == RB_DIR_LEFT || direction == RB_DIR_RIGHT);
+
+       if (self == NULL) {
+#ifndef RBSMALL
+               if (RB_SENTINEL_P(rbt->rbt_root))
+                       return NULL;
+               return rbt->rbt_minmax[direction];
+#else
+               self = rbt->rbt_root;
+               if (RB_SENTINEL_P(self))
+                       return NULL;
+               while (!RB_SENTINEL_P(self->rb_nodes[other]))
+                       self = self->rb_nodes[other];
+               return self;
+#endif /* !RBSMALL */
+       }
+       KASSERT(!RB_SENTINEL_P(self));
+       /*
+        * We can't go any further in this direction.  We proceed up in the
+        * opposite direction until our parent is in direction we want to go.
+        */
+       if (RB_SENTINEL_P(self->rb_nodes[direction])) {
+               while (!RB_ROOT_P(rbt, self)) {
+                       if (other == RB_POSITION(self))
+                               return RB_FATHER(self);
+                       self = RB_FATHER(self);
+               }
+               return NULL;
+       }
+
+       /*
+        * Advance down one in current direction and go down as far as possible
+        * in the opposite direction.
+        */
+       self = self->rb_nodes[direction];
+       KASSERT(!RB_SENTINEL_P(self));
+       while (!RB_SENTINEL_P(self->rb_nodes[other]))
+               self = self->rb_nodes[other];
+       return self;
+}
+
+static unsigned int
+rb_tree_count_black(const struct rb_node *self)
+{
+       unsigned int left, right;
+
+       if (RB_SENTINEL_P(self))
+               return 0;
+
+       left = rb_tree_count_black(self->rb_left);
+       right = rb_tree_count_black(self->rb_right);
+
+       KASSERT(left == right);
+
+       return left + RB_BLACK_P(self);
+}
+
+static bool
+rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self,
+       const struct rb_node *prev, bool red_check)
+{
+       rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes;
+
+       KASSERT(!RB_SENTINEL_P(self));
+       KASSERT(prev == NULL || (*compare_nodes)(prev, self) > 0);
+
+       /*
+        * Verify our relationship to our parent.
+        */
+       if (RB_ROOT_P(rbt, self)) {
+               KASSERT(self == rbt->rbt_root);
+               KASSERT(RB_POSITION(self) == RB_DIR_LEFT);
+               KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_LEFT] == self);
+               KASSERT(RB_FATHER(self) == (const struct rb_node *) &rbt->rbt_root);
+       } else {
+               KASSERT(self != rbt->rbt_root);
+               KASSERT(!RB_FATHER_SENTINEL_P(self));
+               if (RB_POSITION(self) == RB_DIR_LEFT) {
+                       KASSERT((*compare_nodes)(self, RB_FATHER(self)) > 0);
+                       KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_LEFT] == self);
+               } else {
+                       KASSERT((*compare_nodes)(self, RB_FATHER(self)) < 0);
+                       KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_RIGHT] == self);
+               }
+       }
+
+       /*
+        * Verify our position in the linked list against the tree itself.
+        */
+       {
+               const struct rb_node *prev0 = rb_tree_iterate_const(rbt, self, RB_DIR_LEFT);
+               const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_DIR_RIGHT);
+               KASSERT(prev0 == TAILQ_PREV(self, rb_node_qh, rb_link));
+               KASSERT(next0 == TAILQ_NEXT(self, rb_link));
+#ifndef RBSMALL
+               KASSERT(prev0 != NULL || self == rbt->rbt_minmax[RB_DIR_LEFT]);
+               KASSERT(next0 != NULL || self == rbt->rbt_minmax[RB_DIR_RIGHT]);
+#endif
+       }
+
+       /*
+        * The root must be black.
+        * There can never be two adjacent red nodes.
+        */
+       if (red_check) {
+               KASSERT(!RB_ROOT_P(rbt, self) || RB_BLACK_P(self));
+               (void) rb_tree_count_black(self);
+               if (RB_RED_P(self)) {
+                       const struct rb_node *brother;
+                       KASSERT(!RB_ROOT_P(rbt, self));
+                       brother = RB_FATHER(self)->rb_nodes[RB_POSITION(self) ^ RB_DIR_OTHER];
+                       KASSERT(RB_BLACK_P(RB_FATHER(self)));
+                       /*
+                        * I'm red and have no children, then I must either
+                        * have no brother or my brother also be red and
+                        * also have no children.  (black count == 0)
+                        */
+                       KASSERT(!RB_CHILDLESS_P(self)
+                               || RB_SENTINEL_P(brother)
+                               || RB_RED_P(brother)
+                               || RB_CHILDLESS_P(brother));
+                       /*
+                        * If I'm not childless, I must have two children
+                        * and they must be both be black.
+                        */
+                       KASSERT(RB_CHILDLESS_P(self)
+                               || (RB_TWOCHILDREN_P(self)
+                                   && RB_BLACK_P(self->rb_left)
+                                   && RB_BLACK_P(self->rb_right)));
+                       /*
+                        * If I'm not childless, thus I have black children,
+                        * then my brother must either be black or have two
+                        * black children.
+                        */
+                       KASSERT(RB_CHILDLESS_P(self)
+                               || RB_BLACK_P(brother)
+                               || (RB_TWOCHILDREN_P(brother)
+                                   && RB_BLACK_P(brother->rb_left)
+                                   && RB_BLACK_P(brother->rb_right)));
+               } else {
+                       /*
+                        * If I'm black and have one child, that child must
+                        * be red and childless.
+                        */
+                       KASSERT(RB_CHILDLESS_P(self)
+                               || RB_TWOCHILDREN_P(self)
+                               || (!RB_LEFT_SENTINEL_P(self)
+                                   && RB_RIGHT_SENTINEL_P(self)
+                                   && RB_RED_P(self->rb_left)
+                                   && RB_CHILDLESS_P(self->rb_left))
+                               || (!RB_RIGHT_SENTINEL_P(self)
+                                   && RB_LEFT_SENTINEL_P(self)
+                                   && RB_RED_P(self->rb_right)
+                                   && RB_CHILDLESS_P(self->rb_right)));
+
+                       /*
+                        * If I'm a childless black node and my parent is
+                        * black, my 2nd closet relative away from my parent
+                        * is either red or has a red parent or red children.
+                        */
+                       if (!RB_ROOT_P(rbt, self)
+                           && RB_CHILDLESS_P(self)
+                           && RB_BLACK_P(RB_FATHER(self))) {
+                               const unsigned int which = RB_POSITION(self);
+                               const unsigned int other = which ^ RB_DIR_OTHER;
+                               const struct rb_node *relative0, *relative;
+
+                               relative0 = rb_tree_iterate_const(rbt,
+                                   self, other);
+                               KASSERT(relative0 != NULL);
+                               relative = rb_tree_iterate_const(rbt,
+                                   relative0, other);
+                               KASSERT(relative != NULL);
+                               KASSERT(RB_SENTINEL_P(relative->rb_nodes[which]));
+#if 0
+                               KASSERT(RB_RED_P(relative)
+                                       || RB_RED_P(relative->rb_left)
+                                       || RB_RED_P(relative->rb_right)
+                                       || RB_RED_P(RB_FATHER(relative)));
+#endif
+                       }
+               }
+               /*
+                * A grandparent's children must be real nodes and not
+                * sentinels.  First check out grandparent.
+                */
+               KASSERT(RB_ROOT_P(rbt, self)
+                       || RB_ROOT_P(rbt, RB_FATHER(self))
+                       || RB_TWOCHILDREN_P(RB_FATHER(RB_FATHER(self))));
+               /*
+                * If we are have grandchildren on our left, then
+                * we must have a child on our right.
+                */
+               KASSERT(RB_LEFT_SENTINEL_P(self)
+                       || RB_CHILDLESS_P(self->rb_left)
+                       || !RB_RIGHT_SENTINEL_P(self));
+               /*
+                * If we are have grandchildren on our right, then
+                * we must have a child on our left.
+                */
+               KASSERT(RB_RIGHT_SENTINEL_P(self)
+                       || RB_CHILDLESS_P(self->rb_right)
+                       || !RB_LEFT_SENTINEL_P(self));
+
+               /*
+                * If we have a child on the left and it doesn't have two
+                * children make sure we don't have great-great-grandchildren on
+                * the right.
+                */
+               KASSERT(RB_TWOCHILDREN_P(self->rb_left)
+                       || RB_CHILDLESS_P(self->rb_right)
+                       || RB_CHILDLESS_P(self->rb_right->rb_left)
+                       || RB_CHILDLESS_P(self->rb_right->rb_left->rb_left)
+                       || RB_CHILDLESS_P(self->rb_right->rb_left->rb_right)
+                       || RB_CHILDLESS_P(self->rb_right->rb_right)
+                       || RB_CHILDLESS_P(self->rb_right->rb_right->rb_left)
+                       || RB_CHILDLESS_P(self->rb_right->rb_right->rb_right));
+
+               /*
+                * If we have a child on the right and it doesn't have two
+                * children make sure we don't have great-great-grandchildren on
+                * the left.
+                */
+               KASSERT(RB_TWOCHILDREN_P(self->rb_right)
+                       || RB_CHILDLESS_P(self->rb_left)
+                       || RB_CHILDLESS_P(self->rb_left->rb_left)
+                       || RB_CHILDLESS_P(self->rb_left->rb_left->rb_left)
+                       || RB_CHILDLESS_P(self->rb_left->rb_left->rb_right)
+                       || RB_CHILDLESS_P(self->rb_left->rb_right)
+                       || RB_CHILDLESS_P(self->rb_left->rb_right->rb_left)
+                       || RB_CHILDLESS_P(self->rb_left->rb_right->rb_right));
+
+               /*
+                * If we are fully interior node, then our predecessors and
+                * successors must have no children in our direction.
+                */
+               if (RB_TWOCHILDREN_P(self)) {
+                       const struct rb_node *prev0;
+                       const struct rb_node *next0;
+
+                       prev0 = rb_tree_iterate_const(rbt, self, RB_DIR_LEFT);
+                       KASSERT(prev0 != NULL);
+                       KASSERT(RB_RIGHT_SENTINEL_P(prev0));
+
+                       next0 = rb_tree_iterate_const(rbt, self, RB_DIR_RIGHT);
+                       KASSERT(next0 != NULL);
+                       KASSERT(RB_LEFT_SENTINEL_P(next0));
+               }
+       }
+
+       return true;
+}
+
+void
+rb_tree_check(const struct rb_tree *rbt, bool red_check)
+{
+       const struct rb_node *self;
+       const struct rb_node *prev;
+#ifdef RBSTATS
+       unsigned int count = 0;
+#endif
+
+       KASSERT(rbt->rbt_root != NULL);
+       KASSERT(RB_LEFT_P(rbt->rbt_root));
+
+#if defined(RBSTATS) && !defined(RBSMALL)
+       KASSERT(rbt->rbt_count > 1
+           || rbt->rbt_minmax[RB_DIR_LEFT] == rbt->rbt_minmax[RB_DIR_RIGHT]);
+#endif
+
+       prev = NULL;
+       TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) {
+               rb_tree_check_node(rbt, self, prev, false);
+#ifdef RBSTATS
+               count++;
+#endif
+       }
+#ifdef RBSTATS
+       KASSERT(rbt->rbt_count == count);
+#endif
+       if (red_check) {
+               KASSERT(RB_BLACK_P(rbt->rbt_root));
+               KASSERT(RB_SENTINEL_P(rbt->rbt_root)
+                       || rb_tree_count_black(rbt->rbt_root));
+
+               /*
+                * The root must be black.
+                * There can never be two adjacent red nodes.
+                */
+               TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) {
+                       rb_tree_check_node(rbt, self, NULL, true);
+               }
+       }
+}
+#endif /* RBDEBUG */
+
+#ifdef RBSTATS
+static void
+rb_tree_mark_depth(const struct rb_tree *rbt, const struct rb_node *self,
+       size_t *depths, size_t depth)
+{
+       if (RB_SENTINEL_P(self))
+               return;
+
+       if (RB_TWOCHILDREN_P(self)) {
+               rb_tree_mark_depth(rbt, self->rb_left, depths, depth + 1);
+               rb_tree_mark_depth(rbt, self->rb_right, depths, depth + 1);
+               return;
+       }
+       depths[depth]++;
+       if (!RB_LEFT_SENTINEL_P(self)) {
+               rb_tree_mark_depth(rbt, self->rb_left, depths, depth + 1);
+       }
+       if (!RB_RIGHT_SENTINEL_P(self)) {
+               rb_tree_mark_depth(rbt, self->rb_right, depths, depth + 1);
+       }
+}
+
+void
+rb_tree_depths(const struct rb_tree *rbt, size_t *depths)
+{
+       rb_tree_mark_depth(rbt, rbt->rbt_root, depths, 1);
+}
+#endif /* RBSTATS */
diff --git a/SystemConfiguration.fproj/reachability/rb.h b/SystemConfiguration.fproj/reachability/rb.h
new file mode 100644 (file)
index 0000000..56f910d
--- /dev/null
@@ -0,0 +1,195 @@
+/* $NetBSD: rb.h,v 1.13 2009/08/16 10:57:01 yamt Exp $ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas <matt@3am-software.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _SYS_RB_H_
+#define        _SYS_RB_H_
+
+#if defined(_KERNEL) || defined(_STANDALONE)
+#include <sys/types.h>
+#else
+#include <stdbool.h>
+#include <inttypes.h>
+#endif
+#include <sys/queue.h>
+#ifndef __APPLE__
+#include <sys/endian.h>
+#endif
+
+struct rb_node {
+       struct rb_node *rb_nodes[2];
+#define        RB_DIR_LEFT             0
+#define        RB_DIR_RIGHT            1
+#define        RB_DIR_OTHER            1
+#define        rb_left                 rb_nodes[RB_DIR_LEFT]
+#define        rb_right                rb_nodes[RB_DIR_RIGHT]
+
+       /*
+        * rb_info contains the two flags and the parent back pointer.
+        * We put the two flags in the low two bits since we know that
+        * rb_node will have an alignment of 4 or 8 bytes.
+        */
+       uintptr_t rb_info;
+#define        RB_FLAG_POSITION        0x2
+#define        RB_FLAG_RED             0x1
+#define        RB_FLAG_MASK            (RB_FLAG_POSITION|RB_FLAG_RED)
+#define        RB_FATHER(rb) \
+    ((struct rb_node *)((rb)->rb_info & ~RB_FLAG_MASK))
+#define        RB_SET_FATHER(rb, father) \
+    ((void)((rb)->rb_info = (uintptr_t)(father)|((rb)->rb_info & RB_FLAG_MASK)))
+
+#define        RB_SENTINEL_P(rb)       ((rb) == NULL)
+#define        RB_LEFT_SENTINEL_P(rb)  RB_SENTINEL_P((rb)->rb_left)
+#define        RB_RIGHT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_right)
+#define        RB_FATHER_SENTINEL_P(rb) RB_SENTINEL_P(RB_FATHER((rb)))
+#define        RB_CHILDLESS_P(rb) \
+    (RB_SENTINEL_P(rb) || (RB_LEFT_SENTINEL_P(rb) && RB_RIGHT_SENTINEL_P(rb)))
+#define        RB_TWOCHILDREN_P(rb) \
+    (!RB_SENTINEL_P(rb) && !RB_LEFT_SENTINEL_P(rb) && !RB_RIGHT_SENTINEL_P(rb))
+
+#define        RB_POSITION(rb) \
+    (((rb)->rb_info & RB_FLAG_POSITION) ? RB_DIR_RIGHT : RB_DIR_LEFT)
+#define        RB_RIGHT_P(rb)          (RB_POSITION(rb) == RB_DIR_RIGHT)
+#define        RB_LEFT_P(rb)           (RB_POSITION(rb) == RB_DIR_LEFT)
+#define        RB_RED_P(rb)            (!RB_SENTINEL_P(rb) && ((rb)->rb_info & RB_FLAG_RED) != 0)
+#define        RB_BLACK_P(rb)          (RB_SENTINEL_P(rb) || ((rb)->rb_info & RB_FLAG_RED) == 0)
+#define        RB_MARK_RED(rb)         ((void)((rb)->rb_info |= RB_FLAG_RED))
+#define        RB_MARK_BLACK(rb)       ((void)((rb)->rb_info &= ~RB_FLAG_RED))
+#define        RB_INVERT_COLOR(rb)     ((void)((rb)->rb_info ^= RB_FLAG_RED))
+#define        RB_ROOT_P(rbt, rb)      ((rbt)->rbt_root == (rb))
+#define        RB_SET_POSITION(rb, position) \
+    ((void)((position) ? ((rb)->rb_info |= RB_FLAG_POSITION) : \
+    ((rb)->rb_info &= ~RB_FLAG_POSITION)))
+#define        RB_ZERO_PROPERTIES(rb)  ((void)((rb)->rb_info &= ~RB_FLAG_MASK))
+#define        RB_COPY_PROPERTIES(dst, src) \
+    ((void)((dst)->rb_info ^= ((dst)->rb_info ^ (src)->rb_info) & RB_FLAG_MASK))
+#define RB_SWAP_PROPERTIES(a, b) do { \
+    uintptr_t xorinfo = ((a)->rb_info ^ (b)->rb_info) & RB_FLAG_MASK; \
+    (a)->rb_info ^= xorinfo; \
+    (b)->rb_info ^= xorinfo; \
+  } while (/*CONSTCOND*/ 0)
+#ifdef RBDEBUG
+       TAILQ_ENTRY(rb_node) rb_link;
+#endif
+};
+
+#define RB_TREE_MIN(T) rb_tree_iterate((T), NULL, RB_DIR_LEFT)
+#define RB_TREE_MAX(T) rb_tree_iterate((T), NULL, RB_DIR_RIGHT)
+#define RB_TREE_FOREACH(N, T) \
+    for ((N) = RB_TREE_MIN(T); (N); \
+       (N) = rb_tree_iterate((T), (N), RB_DIR_RIGHT))
+#define RB_TREE_FOREACH_REVERSE(N, T) \
+    for ((N) = RB_TREE_MAX(T); (N); \
+       (N) = rb_tree_iterate((T), (N), RB_DIR_LEFT))
+
+#ifdef RBDEBUG
+TAILQ_HEAD(rb_node_qh, rb_node);
+
+#define        RB_TAILQ_REMOVE(a, b, c)                TAILQ_REMOVE(a, b, c)
+#define        RB_TAILQ_INIT(a)                        TAILQ_INIT(a)
+#define        RB_TAILQ_INSERT_HEAD(a, b, c)           TAILQ_INSERT_HEAD(a, b, c)
+#define        RB_TAILQ_INSERT_BEFORE(a, b, c)         TAILQ_INSERT_BEFORE(a, b, c)
+#define        RB_TAILQ_INSERT_AFTER(a, b, c, d)       TAILQ_INSERT_AFTER(a, b, c, d)
+#else
+#define        RB_TAILQ_REMOVE(a, b, c)                do { } while (/*CONSTCOND*/0)
+#define        RB_TAILQ_INIT(a)                        do { } while (/*CONSTCOND*/0)
+#define        RB_TAILQ_INSERT_HEAD(a, b, c)           do { } while (/*CONSTCOND*/0)
+#define        RB_TAILQ_INSERT_BEFORE(a, b, c)         do { } while (/*CONSTCOND*/0)
+#define        RB_TAILQ_INSERT_AFTER(a, b, c, d)       do { } while (/*CONSTCOND*/0)
+#endif /* RBDEBUG */
+
+/*
+ * rbto_compare_nodes_fn:
+ *     return a positive value if the first node < the second node.
+ *     return a negative value if the first node > the second node.
+ *     return 0 if they are considered same.
+ *
+ * rbto_compare_key_fn:
+ *     return a positive value if the node < the key.
+ *     return a negative value if the node > the key.
+ *     return 0 if they are considered same.
+ */
+
+typedef signed int (*const rbto_compare_nodes_fn)(const struct rb_node *,
+    const struct rb_node *);
+typedef signed int (*const rbto_compare_key_fn)(const struct rb_node *,
+    const void *);
+
+struct rb_tree_ops {
+       rbto_compare_nodes_fn rbto_compare_nodes;
+       rbto_compare_key_fn rbto_compare_key;
+};
+
+struct rb_tree {
+       struct rb_node *rbt_root;
+       const struct rb_tree_ops *rbt_ops;
+       struct rb_node *rbt_minmax[2];
+#ifdef RBDEBUG
+       struct rb_node_qh rbt_nodes;
+#endif
+       unsigned int rbt_count;
+#ifdef RBSTATS
+       unsigned int rbt_insertions;
+       unsigned int rbt_removals;
+       unsigned int rbt_insertion_rebalance_calls;
+       unsigned int rbt_insertion_rebalance_passes;
+       unsigned int rbt_removal_rebalance_calls;
+       unsigned int rbt_removal_rebalance_passes;
+#endif
+};
+
+#ifdef RBSTATS
+#define        RBSTAT_INC(v)   ((void)((v)++))
+#define        RBSTAT_DEC(v)   ((void)((v)--))
+#else
+#define        RBSTAT_INC(v)   do { } while (/*CONSTCOND*/0)
+#define        RBSTAT_DEC(v)   do { } while (/*CONSTCOND*/0)
+#endif
+
+void   rb_tree_init(struct rb_tree *, const struct rb_tree_ops *);
+bool   rb_tree_insert_node(struct rb_tree *, struct rb_node *);
+struct rb_node *
+       rb_tree_find_node(struct rb_tree *, const void *);
+struct rb_node *
+       rb_tree_find_node_geq(struct rb_tree *, const void *);
+struct rb_node *
+       rb_tree_find_node_leq(struct rb_tree *, const void *);
+void   rb_tree_remove_node(struct rb_tree *, struct rb_node *);
+struct rb_node *
+       rb_tree_iterate(struct rb_tree *, struct rb_node *, const unsigned int);
+#ifdef RBDEBUG
+void   rb_tree_check(const struct rb_tree *, bool);
+#endif
+#ifdef RBSTATS
+void   rb_tree_depths(const struct rb_tree *, size_t *);
+#endif
+
+#endif /* _SYS_RB_H_*/
diff --git a/SystemConfiguration.fproj/reachability/server.c b/SystemConfiguration.fproj/reachability/server.c
new file mode 100644 (file)
index 0000000..09e97c6
--- /dev/null
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <SystemConfiguration/SCPrivate.h>
+
+#include "SCNetworkReachabilityInternal.h"
+
+int
+main(int argc, char **argv)
+{
+       _sc_log   = FALSE;      // no syslog
+       _sc_debug = TRUE;       // extra reachability logging
+
+       _SCNetworkReachabilityServer_start();
+
+       SCLog(TRUE, LOG_DEBUG, CFSTR("starting CFRunLoop"));
+       CFRunLoopRun();
+       SCLog(TRUE, LOG_DEBUG, CFSTR("CFRunLoop complete"));
+
+       exit(0);
+}
index 7a8b0840499d70e1a05e854961d2af7fe2393457..bb6449735f6e517f474c85d453ea26773458772e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2005, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 __private_extern__ CFMutableDictionaryRef      sessionData             = NULL;
 
 __private_extern__ CFMutableDictionaryRef      storeData               = NULL;
-__private_extern__ CFMutableDictionaryRef      storeData_s             = NULL;
 
 __private_extern__ CFMutableDictionaryRef      patternData             = NULL;
-__private_extern__ CFMutableDictionaryRef      patternData_s           = NULL;
 
 __private_extern__ CFMutableSetRef             changedKeys             = NULL;
-__private_extern__ CFMutableSetRef             changedKeys_s           = NULL;
 
 __private_extern__ CFMutableSetRef             deferredRemovals        = NULL;
-__private_extern__ CFMutableSetRef             deferredRemovals_s      = NULL;
 
 __private_extern__ CFMutableSetRef             removedSessionKeys      = NULL;
-__private_extern__ CFMutableSetRef             removedSessionKeys_s    = NULL;
 
 __private_extern__ CFMutableSetRef             needsNotification       = NULL;
 
-__private_extern__ int                         storeLocked             = 0;            /* > 0 if dynamic store locked */
-
-
-__private_extern__
-void
-_swapLockedStoreData()
-{
-       void    *temp;
-
-       temp                 = storeData;
-       storeData            = storeData_s;
-       storeData_s          = temp;
-
-       temp                 = patternData;
-       patternData          = patternData_s;
-       patternData_s        = temp;
-
-       temp                 = changedKeys;
-       changedKeys          = changedKeys_s;
-       changedKeys_s        = temp;
-
-       temp                 = deferredRemovals;
-       deferredRemovals     = deferredRemovals_s;
-       deferredRemovals_s   = temp;
-
-       temp                 = removedSessionKeys;
-       removedSessionKeys   = removedSessionKeys_s;
-       removedSessionKeys_s = temp;
-
-       return;
-}
-
 
 __private_extern__
 void
index 4b0ea50b511a79aa184ac8a8840c5efdad9b09cf..bcc94e4bc6f1af3b9c854c49c71b6e1cedf33c88 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -77,7 +77,6 @@
 #define        kSCDSessionKeys CFSTR("sessionKeys")
 
 
-extern int                     storeLocked;
 extern CFMutableDictionaryRef  storeData;
 extern CFMutableDictionaryRef  sessionData;
 extern CFMutableDictionaryRef  patternData;
@@ -86,12 +85,6 @@ extern CFMutableSetRef               deferredRemovals;
 extern CFMutableSetRef         removedSessionKeys;
 extern CFMutableSetRef         needsNotification;
 
-extern CFMutableDictionaryRef  storeData_s;
-extern CFMutableDictionaryRef  patternData_s;
-extern CFMutableSetRef         changedKeys_s;
-extern CFMutableSetRef         deferredRemovals_s;
-extern CFMutableSetRef         removedSessionKeys_s;
-
 
 __BEGIN_DECLS
 
@@ -99,16 +92,10 @@ int
 __SCDynamicStoreOpen                   (SCDynamicStoreRef      *store,
                                         CFStringRef            name);
 int
-__SCDynamicStoreClose                  (SCDynamicStoreRef      *store,
-                                        Boolean                internal);
+__SCDynamicStoreClose                  (SCDynamicStoreRef      *store);
 
 int
-__SCDynamicStoreLock                   (SCDynamicStoreRef      store,
-                                        Boolean                recursive);
-
-int
-__SCDynamicStoreUnlock                 (SCDynamicStoreRef      store,
-                                        Boolean                recursive);
+__SCDynamicStorePush                   (void);
 
 int
 __SCDynamicStoreCopyKeyList            (SCDynamicStoreRef      store,
@@ -119,8 +106,7 @@ __SCDynamicStoreCopyKeyList         (SCDynamicStoreRef      store,
 int
 __SCDynamicStoreAddValue               (SCDynamicStoreRef      store,
                                         CFStringRef            key,
-                                        CFDataRef              value,
-                                        Boolean                internal);
+                                        CFDataRef              value);
 
 int
 __SCDynamicStoreCopyValue              (SCDynamicStoreRef      store,
@@ -151,10 +137,6 @@ __SCDynamicStoreRemoveValue                (SCDynamicStoreRef      store,
                                         CFStringRef            key,
                                         Boolean                internal);
 
-int
-__SCDynamicStoreTouchValue             (SCDynamicStoreRef      store,
-                                        CFStringRef            key);
-
 int
 __SCDynamicStoreNotifyValue            (SCDynamicStoreRef      store,
                                         CFStringRef            key,
@@ -202,9 +184,6 @@ __SCDynamicStoreNotifySignal                (SCDynamicStoreRef      store,
 int
 __SCDynamicStoreNotifyCancel           (SCDynamicStoreRef      store);
 
-void
-_swapLockedStoreData                   (void);
-
 void
 _addWatcher                            (CFNumberRef            sessionNum,
                                         CFStringRef            watchedKey);
index e1a0168f88131367faa086936205d92f282a28b3..f532b47a9800698eaee81620037e1b46290a51b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 __private_extern__
 int
-__SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value, Boolean internal)
+__SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value)
 {
-       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
        int                             sc_status       = kSCStatusOK;
+       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
        CFDataRef                       tempValue;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("%s%s : %5d : %@\n"),
-                       internal ? "*add " : "add  ",
+                       "add  ",
                        storePrivate->useSessionKeys ? "t " : "  ",
                        storePrivate->server,
                        key);
        }
 
        /*
-        * 1. Ensure that we hold the lock.
-        */
-       sc_status = __SCDynamicStoreLock(store, TRUE);
-       if (sc_status != kSCStatusOK) {
-               return sc_status;
-       }
-
-       /*
-        * 2. Ensure that this is a new key.
+        * Ensure that this is a new key.
         */
        sc_status = __SCDynamicStoreCopyValue(store, key, &tempValue, TRUE);
        switch (sc_status) {
@@ -86,18 +74,15 @@ __SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val
        }
 
        /*
-        * 3. Save the new key.
+        * Save the new key.
         */
        sc_status = __SCDynamicStoreSetValue(store, key, value, TRUE);
 
-       /*
-        * 4. Release our lock.
-        */
+       /* push changes */
+       __SCDynamicStorePush();
 
     done:
 
-       __SCDynamicStoreUnlock(store, TRUE);
-
        return sc_status;
 }
 
@@ -110,8 +95,8 @@ _configadd(mach_port_t                       server,
           xmlData_t                    dataRef,        /* raw XML bytes */
           mach_msg_type_number_t       dataLen,
           int                          *newInstance,
-          int                          *sc_status
-)
+          int                          *sc_status,
+          audit_token_t                audit_token)
 {
        CFStringRef             key             = NULL;         /* key  (un-serialized) */
        CFDataRef               data            = NULL;         /* data (un-serialized) */
@@ -141,11 +126,20 @@ _configadd(mach_port_t                    server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
+               mySession = tempSession(server, CFSTR("SCDynamicStoreAddValue"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       *sc_status = kSCStatusNoStoreSession;
+                       goto done;
+               }
+       }
+
+       if (!hasWriteAccess(mySession)) {
+               *sc_status = kSCStatusAccessError;
                goto done;
        }
 
-       *sc_status = __SCDynamicStoreAddValue(mySession->store, key, data, FALSE);
+       *sc_status = __SCDynamicStoreAddValue(mySession->store, key, data);
        if (*sc_status == kSCStatusOK) {
                *newInstance = 0;
        }
@@ -167,8 +161,7 @@ _configadd_s(mach_port_t            server,
             xmlData_t                  dataRef,        /* raw XML bytes */
             mach_msg_type_number_t     dataLen,
             int                        *newInstance,
-            int                        *sc_status
-)
+            int                        *sc_status)
 {
        CFDataRef                       data            = NULL;         /* data (un-serialized) */
        CFStringRef                     key             = NULL;         /* key  (un-serialized) */
@@ -199,7 +192,8 @@ _configadd_s(mach_port_t            server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
+               /* you must have an open session to play */
+               *sc_status = kSCStatusNoStoreSession;
                goto done;
        }
 
@@ -208,7 +202,7 @@ _configadd_s(mach_port_t            server,
        useSessionKeys = storePrivate->useSessionKeys;
        storePrivate->useSessionKeys = TRUE;
 
-       *sc_status = __SCDynamicStoreAddValue(mySession->store, key, data, FALSE);
+       *sc_status = __SCDynamicStoreAddValue(mySession->store, key, data);
        if (*sc_status == kSCStatusOK) {
                *newInstance = 0;
        }
index df4a36655e223cd909136fbb076e3ab6ffa6f81a..34e46b36fe1d778715cb939ac735efe405045a04 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003, 2004, 2006-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003, 2004, 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -94,7 +94,7 @@ removeAllKeys(SCDynamicStoreRef store, Boolean isRegex)
 
 __private_extern__
 int
-__SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal)
+__SCDynamicStoreClose(SCDynamicStoreRef *store)
 {
        CFDictionaryRef                 dict;
        CFArrayRef                      keys;
@@ -103,14 +103,9 @@ __SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal)
        CFStringRef                     sessionKey;
        SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)*store;
 
-       if ((*store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
-                       CFSTR("%s : %5d\n"),
-                       internal ? "*close " : "close  ",
+                       CFSTR("close   : %5d\n"),
                        storePrivate->server);
        }
 
@@ -127,48 +122,24 @@ __SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal)
        dict = CFDictionaryGetValue(sessionData, sessionKey);
        keys = CFDictionaryGetValue(dict, kSCDSessionKeys);
        if (keys && ((keyCnt = CFArrayGetCount(keys)) > 0)) {
-               Boolean wasLocked;
                CFIndex i;
+               Boolean push    = FALSE;
 
-               /*
-                * if necessary, claim a lock to ensure that we inform
-                * any processes that a session key was removed.
-                */
-               wasLocked = (storeLocked > 0);
-               if (!wasLocked) {
-                       (void) __SCDynamicStoreLock(*store, FALSE);
-               }
-
-               /* remove keys from "locked" store" */
+               /* remove session keys */
                for (i = 0; i < keyCnt; i++) {
                        if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i))) {
                                (void) __SCDynamicStoreRemoveValue(*store, CFArrayGetValueAtIndex(keys, i), TRUE);
+                               push = TRUE;
                        }
                }
 
-               if (wasLocked) {
-                       /* remove keys from "unlocked" store" */
-                       _swapLockedStoreData();
-                       for (i = 0; i < keyCnt; i++) {
-                               if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i)))
-                                       (void) __SCDynamicStoreRemoveValue(*store, CFArrayGetValueAtIndex(keys, i), TRUE);
-                       }
-                       _swapLockedStoreData();
+               if (push) {
+                       /* push changes */
+                       (void) __SCDynamicStorePush();
                }
-
-               /*
-                * Note: everyone who calls __SCDynamicStoreClose() ends
-                *       up removing this sessions dictionary. As such,
-                *       we don't need to worry about the session keys.
-                */
        }
        CFRelease(sessionKey);
 
-       /* release the lock */
-       if (storePrivate->locked) {
-               (void) __SCDynamicStoreUnlock(*store, FALSE);
-       }
-
        /*
         * invalidate and release our run loop source on the server
         * port (for this client).  Then, release the port.
@@ -191,45 +162,3 @@ __SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal)
 
        return kSCStatusOK;
 }
-
-
-__private_extern__
-kern_return_t
-_configclose(mach_port_t server, int *sc_status)
-{
-       serverSessionRef        mySession = getSession(server);
-
-       if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
-               return KERN_SUCCESS;
-       }
-
-       /*
-        * Close the session.
-        */
-       __MACH_PORT_DEBUG(TRUE, "*** _configclose", server);
-       *sc_status = __SCDynamicStoreClose(&mySession->store, FALSE);
-       if (*sc_status != kSCStatusOK) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("_configclose __SCDynamicStoreClose() failed, status = %s"),
-                     SCErrorString(*sc_status));
-               return KERN_SUCCESS;
-       }
-       __MACH_PORT_DEBUG(TRUE, "*** _configclose (after __SCDynamicStoreClose)", server);
-
-       /*
-        * Remove our receive right.
-        *
-        * Note: there is no need to cancel the notification request because the
-        *       kernel will have no way to deliver the notification once the
-        *       receive right has been removed.
-        */
-       (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1);
-
-       /*
-        * Remove the session entry.
-        */
-       removeSession(server);
-
-       return KERN_SUCCESS;
-}
index 13bc53f6402389d9bdbc2b92a1fae6c4240a64b8..d2a334e515b7a33157ff54aa425e64cd96722a3e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -41,10 +41,6 @@ __SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef *v
        SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
        CFDictionaryRef                 dict;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("%s : %5d : %@\n"),
@@ -73,10 +69,11 @@ _configget(mach_port_t                      server,
           xmlDataOut_t                 *dataRef,       /* raw XML bytes */
           mach_msg_type_number_t       *dataLen,
           int                          *newInstance,
-          int                          *sc_status
-)
+          int                          *sc_status,
+          audit_token_t                audit_token)
 {
        CFStringRef             key             = NULL;         /* key  (un-serialized) */
+       CFIndex                 len;
        serverSessionRef        mySession;
        Boolean                 ok;
        CFDataRef               value;
@@ -97,8 +94,12 @@ _configget(mach_port_t                       server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
-               goto done;
+               mySession = tempSession(server, CFSTR("SCDynamicStoreCopyValue"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       *sc_status = kSCStatusNoStoreSession;
+                       goto done;
+               }
        }
 
        *sc_status = __SCDynamicStoreCopyValue(mySession->store, key, &value, FALSE);
@@ -107,7 +108,8 @@ _configget(mach_port_t                      server,
        }
 
        /* serialize the data */
-       ok = _SCSerializeData(value, (void **)dataRef, (CFIndex *)dataLen);
+       ok = _SCSerializeData(value, (void **)dataRef, &len);
+       *dataLen = len;
        CFRelease(value);
        if (!ok) {
                *sc_status = kSCStatusFailed;
@@ -185,10 +187,6 @@ __SCDynamicStoreCopyMultiple(SCDynamicStoreRef store, CFArrayRef keys, CFArrayRe
        SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
        addSpecific                     myContext;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("copy m  : %5d : %d keys, %d patterns\n"),
@@ -232,10 +230,12 @@ _configget_m(mach_port_t          server,
             mach_msg_type_number_t     patternsLen,
             xmlDataOut_t               *dataRef,
             mach_msg_type_number_t     *dataLen,
-            int                        *sc_status)
+            int                        *sc_status,
+            audit_token_t              audit_token)
 {
        CFDictionaryRef         dict            = NULL; /* keys/values (un-serialized) */
        CFArrayRef              keys            = NULL; /* keys (un-serialized) */
+       CFIndex                 len;
        serverSessionRef        mySession;
        Boolean                 ok;
        CFArrayRef              patterns        = NULL; /* patterns (un-serialized) */
@@ -275,15 +275,20 @@ _configget_m(mach_port_t          server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
-               goto done;
+               mySession = tempSession(server, CFSTR("SCDynamicStoreCopyMultiple"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       *sc_status = kSCStatusNoStoreSession;
+                       goto done;
+               }
        }
 
        /* fetch the requested information */
        *sc_status = __SCDynamicStoreCopyMultiple(mySession->store, keys, patterns, &dict);
 
        /* serialize the dictionary of matching keys/patterns */
-       ok = _SCSerialize(dict, NULL, (void **)dataRef, (CFIndex *)dataLen);
+       ok = _SCSerialize(dict, NULL, (void **)dataRef, &len);
+       *dataLen = len;
        CFRelease(dict);
        if (!ok) {
                *sc_status = kSCStatusFailed;
index cbc7e36cb782bbdd86f4f6cd029e8e3576a3253f..87ba9556ad2d4b25872e91483e289cd6e25e789c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006-2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -41,16 +41,11 @@ __private_extern__
 int
 __SCDynamicStoreCopyKeyList(SCDynamicStoreRef store, CFStringRef key, Boolean isRegex, CFArrayRef *subKeys)
 {
-       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
        CFMutableArrayRef               keyArray;
        CFIndex                         storeCnt;
        CFStringRef                     storeStr;
        CFDictionaryRef                 storeValue;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (isRegex) {
                *subKeys = patternCopyMatches(key);
                return (*subKeys != NULL) ? kSCStatusOK : kSCStatusFailed;
@@ -104,10 +99,11 @@ _configlist(mach_port_t                    server,
            int                         isRegex,
            xmlDataOut_t                *listRef,       /* raw XML bytes */
            mach_msg_type_number_t      *listLen,
-           int                         *sc_status
-)
+           int                         *sc_status,
+           audit_token_t               audit_token)
 {
        CFStringRef             key             = NULL;         /* key  (un-serialized) */
+       CFIndex                 len;
        serverSessionRef        mySession;
        Boolean                 ok;
        CFArrayRef              subKeys;                        /* array of CFStringRef's */
@@ -128,8 +124,12 @@ _configlist(mach_port_t                    server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
-               goto done;
+               mySession = tempSession(server, CFSTR("SCDynamicStoreCopyKeyList"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       *sc_status = kSCStatusNoStoreSession;
+                       goto done;
+               }
        }
 
        *sc_status = __SCDynamicStoreCopyKeyList(mySession->store, key, isRegex != 0, &subKeys);
@@ -138,7 +138,8 @@ _configlist(mach_port_t                     server,
        }
 
        /* serialize the list of keys */
-       ok = _SCSerialize(subKeys, NULL, (void **)listRef, (CFIndex *)listLen);
+       ok = _SCSerialize(subKeys, NULL, (void **)listRef, &len);
+       *listLen = len;
        CFRelease(subKeys);
        if (!ok) {
                *sc_status = kSCStatusFailed;
diff --git a/configd.tproj/_configlock.c b/configd.tproj/_configlock.c
deleted file mode 100644 (file)
index 29b9726..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * Modification History
- *
- * June 1, 2001                        Allan Nathanson <ajn@apple.com>
- * - public API conversion
- *
- * March 24, 2000              Allan Nathanson <ajn@apple.com>
- * - initial revision
- */
-
-#include "configd.h"
-#include "configd_server.h"
-#include "session.h"
-
-
-__private_extern__
-int
-__SCDynamicStoreLock(SCDynamicStoreRef store, Boolean recursive)
-{
-       serverSessionRef                mySession;
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession;         /* you must have an open session to play */
-       }
-
-       if (storeLocked > 0) {
-               if (storePrivate->locked && recursive) {
-                       /* if this session holds the lock and this is a recursive (internal) request */
-                       storeLocked++;
-                       return kSCStatusOK;
-               }
-               return kSCStatusLocked;                 /* sorry, someone (you) already have the lock */
-       }
-
-       /* check credentials */
-       mySession = getSession(storePrivate->server);
-       if (!hasWriteAccess(mySession)) {
-               return kSCStatusAccessError;
-       }
-
-       if (!recursive && _configd_trace) {
-               SCTrace(TRUE, _configd_trace, CFSTR("lock    : %5d\n"), storePrivate->server);
-       }
-
-       storeLocked          = 1;       /* global lock flag */
-       storePrivate->locked = TRUE;    /* per-session lock flag */
-
-       /*
-        * defer all (actually, most) changes until the call to __SCDynamicStoreUnlock()
-        */
-       if (storeData_s) {
-               CFRelease(storeData_s);
-               CFRelease(patternData_s);
-               CFRelease(changedKeys_s);
-               CFRelease(deferredRemovals_s);
-               CFRelease(removedSessionKeys_s);
-       }
-       storeData_s          = CFDictionaryCreateMutableCopy(NULL, 0, storeData);
-       patternData_s        = CFDictionaryCreateMutableCopy(NULL, 0, patternData);
-       changedKeys_s        = CFSetCreateMutableCopy(NULL, 0, changedKeys);
-       deferredRemovals_s   = CFSetCreateMutableCopy(NULL, 0, deferredRemovals);
-       removedSessionKeys_s = CFSetCreateMutableCopy(NULL, 0, removedSessionKeys);
-
-       /* Add a "locked" mode run loop source for this port */
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, CFSTR("locked"));
-
-       return kSCStatusOK;
-}
-
-
-__private_extern__
-kern_return_t
-_configlock(mach_port_t server, int *sc_status)
-{
-       serverSessionRef        mySession = getSession(server);
-
-       if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
-               return KERN_SUCCESS;
-       }
-
-       *sc_status = __SCDynamicStoreLock(mySession->store, FALSE);
-       if (*sc_status != kSCStatusOK) {
-               return KERN_SUCCESS;
-       }
-
-       return KERN_SUCCESS;
-}
index ab26edf50593c2dde2428e9895bb4288788ca4cc..52db0f86e58f4c020e475b17c08247c9896d26fe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -35,16 +35,12 @@ __private_extern__
 int
 __SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key, Boolean internal)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-       int                             sc_status       = kSCStatusOK;
        CFDictionaryRef                 dict;
        Boolean                         newValue        = FALSE;
+       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
+       int                             sc_status       = kSCStatusOK;
        CFDataRef                       value;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("%s : %5d : %@\n"),
@@ -54,15 +50,7 @@ __SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key, Boolean in
        }
 
        /*
-        * 1. Ensure that we hold the lock.
-        */
-       sc_status = __SCDynamicStoreLock(store, TRUE);
-       if (sc_status != kSCStatusOK) {
-               return sc_status;
-       }
-
-       /*
-        * 2. Tickle the value in the dynamic store
+        * Tickle the value in the dynamic store
         */
        dict = CFDictionaryGetValue(storeData, key);
        if (!dict || !CFDictionaryGetValueIfPresent(dict, kSCDData, (const void **)&value)) {
@@ -80,10 +68,10 @@ __SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key, Boolean in
                CFRelease(value);
        }
 
-       /*
-        * 3. Release our lock.
-        */
-       __SCDynamicStoreUnlock(store, TRUE);
+       if (!internal) {
+               /* push changes */
+               __SCDynamicStorePush();
+       }
 
        return sc_status;
 }
@@ -94,8 +82,8 @@ kern_return_t
 _confignotify(mach_port_t              server,
              xmlData_t                 keyRef,         /* raw XML bytes */
              mach_msg_type_number_t    keyLen,
-             int                       *sc_status
-)
+             int                       *sc_status,
+             audit_token_t             audit_token)
 {
        CFStringRef             key             = NULL;         /* key  (un-serialized) */
        serverSessionRef        mySession;
@@ -113,7 +101,16 @@ _confignotify(mach_port_t          server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
+               mySession = tempSession(server, CFSTR("SCDynamicStoreNotifyValue"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       *sc_status = kSCStatusNoStoreSession;
+                       goto done;
+               }
+       }
+
+       if (!hasWriteAccess(mySession)) {
+               *sc_status = kSCStatusAccessError;
                goto done;
        }
 
index 5f70aeb5338c17b6751e544c984670c0299e8eb5..07a49f9613e60845c6985423a2fcee11d9cda686 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -149,8 +149,11 @@ _configopen(mach_port_t                    server,
                }
        }
 
-       mySession = getSession(server);
-       if ((mySession != NULL) && (mySession->store != NULL)) {
+       /*
+        * establish the new session
+        */
+       mySession = addSession(server, openMPCopyDescription);
+       if (mySession == NULL) {
 #ifdef DEBUG
                SCLog(TRUE, LOG_DEBUG, CFSTR("_configopen(): session is already open."));
 #endif /* DEBUG */
@@ -158,10 +161,6 @@ _configopen(mach_port_t                    server,
                goto done;
        }
 
-       /*
-        * establish the new session
-        */
-       mySession = addSession(MACH_PORT_NULL, openMPCopyDescription);
        *newServer = mySession->key;
        __MACH_PORT_DEBUG(TRUE, "*** _configopen (after addSession)", *newServer);
 
index 9bb06b88a33ba67124f01e23fb610185fbb602a5..2d43008f26b9a17f468b9c44da9e8e46f82602f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -38,16 +38,12 @@ __private_extern__
 int
 __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean internal)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-       int                             sc_status = kSCStatusOK;
        CFDictionaryRef                 dict;
        CFMutableDictionaryRef          newDict;
+       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
+       int                             sc_status       = kSCStatusOK;
        CFStringRef                     sessionKey;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("%s : %5d : %@\n"),
@@ -57,15 +53,7 @@ __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean in
        }
 
        /*
-        * 1. Ensure that we hold the lock.
-        */
-       sc_status = __SCDynamicStoreLock(store, TRUE);
-       if (sc_status != kSCStatusOK) {
-               return sc_status;
-       }
-
-       /*
-        * 2. Ensure that this key exists.
+        * Ensure that this key exists.
         */
        dict = CFDictionaryGetValue(storeData, key);
        if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDData) == FALSE)) {
@@ -76,21 +64,21 @@ __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean in
        newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
 
        /*
-        * 3. Mark this key as "changed". Any "watchers" will be
-        *    notified as soon as the lock is released.
+        * Mark this key as "changed". Any "watchers" will be
+        * notified as soon as the lock is released.
         */
        CFSetAddValue(changedKeys, key);
 
        /*
-        * 4. Add this key to a deferred cleanup list so that, after
-        *    the change notifications are posted, any associated
-        *    regex keys can be removed.
+        * Add this key to a deferred cleanup list so that, after
+        * the change notifications are posted, any associated
+        * regex keys can be removed.
         */
        CFSetAddValue(deferredRemovals, key);
 
        /*
-        * 5. Check if this is a session key and, if so, add it
-        *    to the (session) removal list
+        * Check if this is a session key and, if so, add it
+        * to the (session) removal list
         */
        sessionKey = CFDictionaryGetValue(newDict, kSCDSession);
        if (sessionKey) {
@@ -106,7 +94,7 @@ __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean in
        }
 
        /*
-        * 6. Remove data and update/remove the dictionary store entry.
+        * Remove data and update/remove the dictionary store entry.
         */
        CFDictionaryRemoveValue(newDict, kSCDData);
        if (CFDictionaryGetCount(newDict) > 0) {
@@ -118,11 +106,12 @@ __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean in
        }
        CFRelease(newDict);
 
-       /*
-        * 7. Release our lock.
-        */
+       if (!internal) {
+               /* push changes */
+               __SCDynamicStorePush();
+       }
+
     done:
-       __SCDynamicStoreUnlock(store, TRUE);
 
        return sc_status;
 }
@@ -133,8 +122,8 @@ kern_return_t
 _configremove(mach_port_t              server,
              xmlData_t                 keyRef,         /* raw XML bytes */
              mach_msg_type_number_t    keyLen,
-             int                       *sc_status
-)
+             int                       *sc_status,
+             audit_token_t             audit_token)
 {
        CFStringRef             key             = NULL;         /* key  (un-serialized) */
        serverSessionRef        mySession;
@@ -152,7 +141,16 @@ _configremove(mach_port_t          server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
+               mySession = tempSession(server, CFSTR("SCDynamicStoreRemoveValue"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       *sc_status = kSCStatusNoStoreSession;
+                       goto done;
+               }
+       }
+
+       if (!hasWriteAccess(mySession)) {
+               *sc_status = kSCStatusAccessError;
                goto done;
        }
 
index a15b3ece0ba2f8f0ad40d9d4a7e795a6317b4097..ee05645aa2edc85c7824619f00ad59e1d1457abb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -41,18 +41,14 @@ __private_extern__
 int
 __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value, Boolean internal)
 {
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-       int                             sc_status       = kSCStatusOK;
        CFDictionaryRef                 dict;
        CFMutableDictionaryRef          newDict;
        Boolean                         newEntry        = FALSE;
+       int                             sc_status       = kSCStatusOK;
        CFStringRef                     sessionKey;
+       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
        CFStringRef                     storeSessionKey;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("%s%s : %5d : %@\n"),
@@ -63,15 +59,7 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val
        }
 
        /*
-        * 1. Ensure that we hold the lock.
-        */
-       sc_status = __SCDynamicStoreLock(store, TRUE);
-       if (sc_status != kSCStatusOK) {
-               return sc_status;
-       }
-
-       /*
-        * 2. Grab the current (or establish a new) dictionary for this key.
+        * Grab the current (or establish a new) dictionary for this key.
         */
 
        dict = CFDictionaryGetValue(storeData, key);
@@ -87,7 +75,7 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val
        }
 
        /*
-        * 3. Update the dictionary entry to be saved to the store.
+        * Update the dictionary entry to be saved to the store.
         */
        newEntry = !CFDictionaryContainsKey(newDict, kSCDData);
        CFDictionarySetValue(newDict, kSCDData, value);
@@ -95,7 +83,7 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val
        sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
 
        /*
-        * 4. Manage per-session keys.
+        * Manage per-session keys.
         */
        if (storePrivate->useSessionKeys) {
                if (newEntry) {
@@ -180,20 +168,20 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val
        CFRelease(sessionKey);
 
        /*
-        * 5. Update the dictionary entry in the store.
+        * Update the dictionary entry in the store.
         */
 
        CFDictionarySetValue(storeData, key, newDict);
        CFRelease(newDict);
 
        /*
-        * 6. For "new" entries to the store, check the deferred cleanup
-        *    list. If the key is flagged for removal, remove it from the
-        *    list since any defined regex's for this key are still defined
-        *    and valid. If the key is not flagged then iterate over the
-        *    sessionData dictionary looking for regex keys which match the
-        *    updated key. If a match is found then we mark those keys as
-        *    being watched.
+        * For "new" entries to the store, check the deferred cleanup
+        * list. If the key is flagged for removal, remove it from the
+        * list since any defined regex's for this key are still defined
+        * and valid. If the key is not flagged then iterate over the
+        * sessionData dictionary looking for regex keys which match the
+        * updated key. If a match is found then we mark those keys as
+        * being watched.
         */
 
        if (newEntry) {
@@ -205,17 +193,17 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val
        }
 
        /*
-        * 7. Mark this key as "changed". Any "watchers" will be notified
-        *    as soon as the lock is released.
+        * Mark this key as "changed". Any "watchers" will be notified
+        * as soon as the lock is released.
         */
        CFSetAddValue(changedKeys, key);
 
     done :
 
-       /*
-        * 8. Release our lock.
-        */
-       __SCDynamicStoreUnlock(store, TRUE);
+       if (!internal) {
+               /* push changes */
+               __SCDynamicStorePush();
+       }
 
        return sc_status;
 }
@@ -229,8 +217,8 @@ _configset(mach_port_t                      server,
           mach_msg_type_number_t       dataLen,
           int                          oldInstance,
           int                          *newInstance,
-          int                          *sc_status
-)
+          int                          *sc_status,
+          audit_token_t                audit_token)
 {
        CFDataRef               data            = NULL; /* data (un-serialized) */
        CFStringRef             key             = NULL; /* key  (un-serialized) */
@@ -259,7 +247,16 @@ _configset(mach_port_t                     server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
+               mySession = tempSession(server, CFSTR("SCDynamicStoreSetValue"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       *sc_status = kSCStatusNoStoreSession;
+                       goto done;
+               }
+       }
+
+       if (!hasWriteAccess(mySession)) {
+               *sc_status = kSCStatusAccessError;
                goto done;
        }
 
@@ -327,12 +324,8 @@ __private_extern__
 int
 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFArrayRef keysToNotify)
 {
-       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
        int                             sc_status       = kSCStatusOK;
-
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
+       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
 
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
@@ -343,14 +336,6 @@ __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet,
                        keysToNotify ? CFArrayGetCount     (keysToNotify) : 0);
        }
 
-       /*
-        * Ensure that we hold the lock
-        */
-       sc_status = __SCDynamicStoreLock(store, TRUE);
-       if (sc_status != kSCStatusOK) {
-               return sc_status;
-       }
-
        /*
         * Set the new/updated keys
         */
@@ -380,8 +365,8 @@ __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet,
                                     (void *)store);
        }
 
-       /* Release our lock */
-       __SCDynamicStoreUnlock(store, TRUE);
+       /* push changes */
+       __SCDynamicStorePush();
 
        return sc_status;
 }
@@ -395,7 +380,8 @@ _configset_m(mach_port_t            server,
             mach_msg_type_number_t     removeLen,
             xmlData_t                  notifyRef,
             mach_msg_type_number_t     notifyLen,
-            int                        *sc_status)
+            int                        *sc_status,
+            audit_token_t              audit_token)
 {
        CFDictionaryRef         dict            = NULL;         /* key/value dictionary (un-serialized) */
        serverSessionRef        mySession;
@@ -446,8 +432,16 @@ _configset_m(mach_port_t           server,
 
        mySession = getSession(server);
        if (mySession == NULL) {
-               /* you must have an open session to play */
-               *sc_status = kSCStatusNoStoreSession;
+               mySession = tempSession(server, CFSTR("SCDynamicStoreSetMultiple"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       *sc_status = kSCStatusNoStoreSession;
+                       goto done;
+               }
+       }
+
+       if (!hasWriteAccess(mySession)) {
+               *sc_status = kSCStatusAccessError;
                goto done;
        }
 
diff --git a/configd.tproj/_configtouch.c b/configd.tproj/_configtouch.c
deleted file mode 100644 (file)
index fb30131..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (c) 2000-2004, 2006, 2008, 2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * Modification History
- *
- * June 1, 2001                        Allan Nathanson <ajn@apple.com>
- * - public API conversion
- *
- * June 20, 2000               Allan Nathanson <ajn@apple.com>
- * - initial revision
- */
-
-#include "configd.h"
-#include "session.h"
-
-__private_extern__
-int
-__SCDynamicStoreTouchValue(SCDynamicStoreRef store, CFStringRef key)
-{
-       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
-       int                             sc_status       = kSCStatusOK;
-       CFDataRef                       value;
-
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
-       if (_configd_trace) {
-               SCTrace(TRUE, _configd_trace, CFSTR("touch   : %5d : %@\n"), storePrivate->server, key);
-       }
-
-       /*
-        * 1. Ensure that we hold the lock.
-        */
-       sc_status = __SCDynamicStoreLock(store, TRUE);
-       if (sc_status != kSCStatusOK) {
-               return sc_status;
-       }
-
-       /*
-        * 2. Grab the current (or establish a new) store entry for this key.
-        */
-       sc_status = __SCDynamicStoreCopyValue(store, key, &value, TRUE);
-       switch (sc_status) {
-               case kSCStatusNoKey : {
-                       CFDateRef       now;
-
-                       /* store entry does not exist, create */
-
-                       now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
-                       (void) _SCSerialize(now, &value, NULL, NULL);
-                       CFRelease(now);
-                       break;
-               }
-
-               case kSCStatusOK : {
-                       CFDateRef       now;
-
-                       /* store entry exists */
-
-                       (void) _SCUnserialize((CFPropertyListRef *)&now, value, NULL, 0);
-                       if (isA_CFDate(now)) {
-                               /* the value is a CFDate, update the time stamp */
-                               CFRelease(now);
-                               CFRelease(value);
-                               now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
-                               (void) _SCSerialize(now, &value, NULL, NULL);
-                       } /* else, we'll just save the data (again) to bump the instance */
-                       CFRelease(now);
-
-                       break;
-               }
-               default :
-                       goto done;
-       }
-
-       sc_status = __SCDynamicStoreSetValue(store, key, value, TRUE);
-       CFRelease(value);
-
-    done :
-
-       /*
-        * 8. Release our lock.
-        */
-       __SCDynamicStoreUnlock(store, TRUE);
-
-       return sc_status;
-}
-
-
-__private_extern__
-kern_return_t
-_configtouch(mach_port_t               server,
-            xmlData_t                  keyRef,         /* raw XML bytes */
-            mach_msg_type_number_t     keyLen,
-            int                        *sc_status
-)
-{
-       CFStringRef             key             = NULL;         /* key  (un-serialized) */
-       serverSessionRef        mySession;
-
-       /* un-serialize the key */
-       if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) {
-               *sc_status = kSCStatusFailed;
-               goto done;
-       }
-
-       if (!isA_CFString(key)) {
-               *sc_status = kSCStatusInvalidArgument;
-               goto done;
-       }
-
-       mySession = getSession(server);
-       if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
-               goto done;
-       }
-
-       *sc_status = __SCDynamicStoreTouchValue(mySession->store, key);
-
-    done :
-
-       if (key)        CFRelease(key);
-       return KERN_SUCCESS;
-}
index e441ec3b14ce133212ccb178478eeb5b8ee4c0ec..c5df46379a19c30a99b94fc450da923b5ce8d059 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -250,38 +250,8 @@ _cleanupRemovedSessionKeys(const void *value, void *context)
 
 __private_extern__
 int
-__SCDynamicStoreUnlock(SCDynamicStoreRef store, Boolean recursive)
+__SCDynamicStorePush(void)
 {
-       serverSessionRef                mySession;
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
-
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession;         /* you must have an open session to play */
-       }
-
-       if ((storeLocked == 0) || !storePrivate->locked) {
-               return kSCStatusNeedLock;               /* sorry, you don't have the lock */
-       }
-
-       if ((storeLocked > 1) && recursive) {
-               /* if the lock is being held for a recursive (internal) request */
-               storeLocked--;
-               return kSCStatusOK;
-       }
-
-       if (!recursive && _configd_trace) {
-               SCTrace(TRUE, _configd_trace, CFSTR("unlock  : %5d\n"), storePrivate->server);
-       }
-
-       /*
-        * all of the changes can be committed to the (real) store.
-        */
-       CFDictionaryRemoveAllValues(storeData_s);
-       CFDictionaryRemoveAllValues(patternData_s);
-       CFSetRemoveAllValues       (changedKeys_s);
-       CFSetRemoveAllValues       (deferredRemovals_s);
-       CFSetRemoveAllValues       (removedSessionKeys_s);
-
        /*
         * push notifications to any session watching those keys which
         * were recently changed.
@@ -299,32 +269,5 @@ __SCDynamicStoreUnlock(SCDynamicStoreRef store, Boolean recursive)
        CFSetApplyFunction(removedSessionKeys, _cleanupRemovedSessionKeys, NULL);
        CFSetRemoveAllValues(removedSessionKeys);
 
-       /* Remove the "locked" run loop source for this port */
-       mySession = getSession(storePrivate->server);
-       CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, CFSTR("locked"));
-
-       storeLocked          = 0;       /* global lock flag */
-       storePrivate->locked = FALSE;   /* per-session lock flag */
-
        return kSCStatusOK;
 }
-
-
-__private_extern__
-kern_return_t
-_configunlock(mach_port_t server, int *sc_status)
-{
-       serverSessionRef        mySession = getSession(server);
-
-       if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
-               return KERN_SUCCESS;
-       }
-
-       *sc_status = __SCDynamicStoreUnlock(mySession->store, FALSE);
-       if (*sc_status != kSCStatusOK) {
-               return KERN_SUCCESS;
-       }
-
-       return KERN_SUCCESS;
-}
index 5fd22f654073bed8b8e5dbb93001e41ad275c3a0..22468ffefe3d89c275f3a0eb36c960afaad80a69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2008, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -89,10 +89,6 @@ __SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean
        CFNumberRef                     sessionNum      = NULL;
        SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("%s : %5d : %s : %@\n"),
@@ -250,10 +246,6 @@ __SCDynamicStoreSetNotificationKeys(SCDynamicStoreRef store, CFArrayRef keys, CF
        updateKeysContext               myContext;
        SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("watch   : %5d : %d keys, %d patterns\n"),
index 1c1ec6f9e111a4d5400faa1f8389efc9a410e4aa..a40fb6e4fd9725da7f2bf4001d06eab642cd785d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003, 2006, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -43,10 +43,6 @@ __SCDynamicStoreCopyNotifiedKeys(SCDynamicStoreRef store, CFArrayRef *notifierKe
        CFDictionaryRef                 info;
        CFMutableDictionaryRef          newInfo;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
        info = CFDictionaryGetValue(sessionData, sessionKey);
        if ((info == NULL) ||
@@ -81,6 +77,7 @@ _notifychanges(mach_port_t                    server,
               int                              *sc_status
 )
 {
+       CFIndex                 len;
        serverSessionRef        mySession = getSession(server);
        CFArrayRef              notifierKeys;   /* array of CFStringRef's */
        Boolean                 ok;
@@ -99,7 +96,8 @@ _notifychanges(mach_port_t                    server,
        }
 
        /* serialize the array of keys */
-       ok = _SCSerialize(notifierKeys, NULL, (void **)listRef, (CFIndex *)listLen);
+       ok = _SCSerialize(notifierKeys, NULL, (void **)listRef, &len);
+       *listLen = len;
        CFRelease(notifierKeys);
        if (!ok) {
                *sc_status = kSCStatusFailed;
index 5af640556d8900b0886b457cfc79eb3d0e38f6ff..bd4a261e328c65d0a8e9f530d5db756cdae92f0e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2008, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -69,10 +69,6 @@ __SCDynamicStoreRemoveWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boole
        CFNumberRef                     sessionNum;
        SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)store;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (_configd_trace) {
                SCTrace(TRUE, _configd_trace,
                        CFSTR("%s : %5d : %s : %@\n"),
index 2cda2b78eb0ba45595d2787a92fa9bc3739d67ad..f855c6bd433053ebafe5b45c983502ff80873351 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2006, 2008-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2006, 2008-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -53,10 +53,6 @@ __SCDynamicStoreNotifyFileDescriptor(SCDynamicStoreRef       store,
        CFStringRef                     sessionKey;
        CFDictionaryRef                 info;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (storePrivate->notifyStatus != NotifierNotRegistered) {
                /* sorry, you can only have one notification registered at once */
                return kSCStatusNotifierActive;
index 84561085389237190b6012a6f9abdac307e1023b..8f52a7822a9df083b479453b48eaaf6cb9ed6421 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -44,10 +44,6 @@ __SCDynamicStoreNotifyMachPort(SCDynamicStoreRef     store,
        CFStringRef                     sessionKey;
        CFDictionaryRef                 info;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession;         /* you must have an open session to play */
-       }
-
        if (storePrivate->notifyStatus != NotifierNotRegistered) {
                /* sorry, you can only have one notification registered at once */
                return kSCStatusNotifierActive;
index 4021c400785d45622319f30f4a74496fd485420e..9d15ce935bf894b0394a48f5577725715a2792e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2006, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -46,10 +46,6 @@ __SCDynamicStoreNotifySignal(SCDynamicStoreRef store, pid_t pid, int sig)
        CFStringRef                     sessionKey;
        CFDictionaryRef                 info;
 
-       if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
-               return kSCStatusNoStoreSession; /* you must have an open session to play */
-       }
-
        if (storePrivate->notifyStatus != NotifierNotRegistered) {
                /* sorry, you can only have one notification registered at once */
                return kSCStatusNotifierActive;
index 2c94f852e5772388995d71ea5b46e995f8cf45c5..be7b77b3ee30139729e3cfef7fd002e5f4a17171 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2006, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2006, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -49,7 +49,7 @@
 
 #define N_QUICK        100
 
-static CFDictionaryRef
+static CF_RETURNS_RETAINED CFDictionaryRef
 _expandStore(CFDictionaryRef storeData)
 {
        const void *            keys_q[N_QUICK];
@@ -125,17 +125,8 @@ __SCDynamicStoreSnapshot(SCDynamicStoreRef store)
        CFDictionaryRef                 expandedStoreData;
        FILE                            *f;
        int                             fd;
-       serverSessionRef                mySession;
-       SCDynamicStorePrivateRef        storePrivate = (SCDynamicStorePrivateRef)store;
        CFDataRef                       xmlData;
 
-       /* check credentials */
-
-       mySession = getSession(storePrivate->server);
-       if (!hasRootAccess(mySession)) {
-               return kSCStatusAccessError;
-       }
-
        /* Save a snapshot of configd's "state" */
 
        (void) unlink(SNAPSHOT_PATH_STATE);
@@ -218,13 +209,21 @@ __SCDynamicStoreSnapshot(SCDynamicStoreRef store)
 
 __private_extern__
 kern_return_t
-_snapshot(mach_port_t server, int *sc_status)
+_snapshot(mach_port_t server, int *sc_status, audit_token_t audit_token)
 {
-       serverSessionRef        mySession = getSession(server);
+       serverSessionRef        mySession;
 
+       mySession = getSession(server);
        if (mySession == NULL) {
-               *sc_status = kSCStatusNoStoreSession;   /* you must have an open session to play */
-               return KERN_SUCCESS;
+               mySession = tempSession(server, CFSTR("SCDynamicStoreSnapshot"), audit_token);
+               if (mySession == NULL) {
+                       /* you must have an open session to play */
+                       return kSCStatusNoStoreSession;
+               }
+       }
+
+       if (!hasRootAccess(mySession)) {
+               return kSCStatusAccessError;
        }
 
        *sc_status = __SCDynamicStoreSnapshot(mySession->store);
index 3ffea54199ac933318772a8e59f86e6c41c8e858..33473f19a316b9c0f7ec5b1db77b8e60aa73c69f 100644 (file)
        <dict>
                <key>com.apple.SystemConfiguration.configd</key>
                <true/>
+               <key>com.apple.SystemConfiguration.SCNetworkReachability</key>
+               <true/>
        </dict>
+       <key>POSIXSpawnType</key>
+       <string>Interactive</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/libexec/configd</string>
index ce441fa1b065ac9d8c41b2a68ae32a9d416038de..0a6b13c8c2de784593b57945e184d134bb95ab4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003, 2006, 2007, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -53,6 +53,7 @@
 
 extern Boolean         _configd_verbose;       /* TRUE if verbose logging enabled */
 extern FILE            *_configd_trace;        /* non-NULL if tracing enabled */
+extern CFMutableSetRef _plugins_allowed;       /* bundle identifiers to allow when loading */
 extern CFMutableSetRef _plugins_exclude;       /* bundle identifiers to exclude from loading */
 extern Boolean         _plugins_fork;          /* TRUE if plugins should be exec'd in their own process */
 extern CFMutableSetRef _plugins_verbose;       /* bundle identifiers to enable verbose logging */
index d701c2428e377bcec14ec72c342a0f643ac460fa..0a527297db532ac331af94e5379dda028376bb3d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -34,7 +34,7 @@
  * - created
  */
 
-//#define DO_NOT_INFORM
+#define DO_NOT_INFORM
 
 #include <getopt.h>
 #include <stdio.h>
@@ -65,6 +65,9 @@ Boolean       _configd_verbose                = FALSE;        /* TRUE if verbose logging enabled */
 __private_extern__
 FILE   *_configd_trace                 = NULL;         /* non-NULL if tracing enabled */
 
+__private_extern__
+CFMutableSetRef        _plugins_allowed        = NULL;         /* bundle identifiers to allow when loading */
+
 __private_extern__
 CFMutableSetRef        _plugins_exclude        = NULL;         /* bundle identifiers to exclude from loading */
 
@@ -78,6 +81,7 @@ static CFMachPortRef termRequested    = NULL;         /* Mach port used to notify runloop
 
 
 static const struct option longopts[] = {
+//     { "include-plugin",     required_argument,      0,      'A' },
 //     { "no-bundles",         no_argument,            0,      'b' },
 //     { "exclude-plugin",     required_argument,      0,      'B' },
 //     { "no-fork",            no_argument,            0,      'd' },
@@ -93,7 +97,7 @@ static const struct option longopts[] = {
 static void
 usage(const char *prog)
 {
-       SCPrint(TRUE, stderr, CFSTR("%s: [-d] [-v] [-V bundleID] [-b] [-B bundleID] [-t bundle-path]\n"), prog);
+       SCPrint(TRUE, stderr, CFSTR("%s: [-d] [-v] [-V bundleID] [-b] [-B bundleID] [-A bundleID] [-t bundle-path]\n"), prog);
        SCPrint(TRUE, stderr, CFSTR("options:\n"));
        SCPrint(TRUE, stderr, CFSTR("\t-d\tdisable daemon/run in foreground\n"));
        SCPrint(TRUE, stderr, CFSTR("\t-v\tenable verbose logging\n"));
@@ -101,6 +105,7 @@ usage(const char *prog)
        SCPrint(TRUE, stderr, CFSTR("\t-f\tload ALL plug-ins in a separate process\n"));
        SCPrint(TRUE, stderr, CFSTR("\t-b\tdisable loading of ALL plug-ins\n"));
        SCPrint(TRUE, stderr, CFSTR("\t-B\tdisable loading of the specified plug-in\n"));
+       SCPrint(TRUE, stderr, CFSTR("\t-A\tenable loading of the specified plug-in\n"));
        SCPrint(TRUE, stderr, CFSTR("\t-t\tload/test the specified plug-in\n"));
        SCPrint(TRUE, stderr, CFSTR("\t\t  (Note: only the plug-in will be started)\n"));
        exit (EX_USAGE);
@@ -260,20 +265,6 @@ fork_child()
        return 0;
 }
 
-
-static void
-writepid(void)
-{
-       FILE *fp;
-
-       fp = fopen("/var/run/configd.pid", "w");
-       if (fp != NULL) {
-               fprintf(fp, "%d\n", getpid());
-               fclose(fp);
-       }
-}
-
-
 static CFStringRef
 termMPCopyDescription(const void *info)
 {
@@ -297,20 +288,26 @@ main(int argc, char * const argv[])
        Boolean                 loadBundles     = TRUE;
        struct sigaction        nact;
        int                     opt;
-       extern int              optind;
+//     extern int              optind;
        const char              *prog           = argv[0];
        CFRunLoopSourceRef      rls;
        kern_return_t           status;
        CFStringRef             str;
        const char              *testBundle     = NULL;
 
+       _plugins_allowed = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
        _plugins_exclude = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
        _plugins_verbose = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
 
        /* process any arguments */
 
-       while ((opt = getopt_long(argc, argv, "bB:dt:vV:f", longopts, NULL)) != -1) {
+       while ((opt = getopt_long(argc, argv, "A:bB:dt:vV:f", longopts, NULL)) != -1) {
                switch(opt) {
+                       case 'A':
+                               str = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingMacRoman);
+                               CFSetSetValue(_plugins_allowed, str);
+                               CFRelease(str);
+                               break;
                        case 'b':
                                loadBundles = FALSE;
                                break;
@@ -437,11 +434,6 @@ main(int argc, char * const argv[])
        /* check/enable trace logging */
        set_trace();
 
-       /* record process id */
-       if (testBundle == NULL) {
-               writepid();
-       }
-
        /* add signal handler to catch a SIGHUP */
        nact.sa_handler = catcher;
        sigemptyset(&nact.sa_mask);
index dce8172da878c1613b4a676bd25ec52b771a86d8..99240d50217ec84e06cb3b8d333216d637c2019f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -251,14 +251,10 @@ server_init()
 
        /*
         * Create and add a run loop source for the port and add this source
-        * to both the default run loop mode and the "locked" mode. These two
-        * modes will be used for normal (unlocked) communication with the
-        * server and when multiple (locked) updates are requested by a single
-        * session.
+        * to the default run loop mode.
         */
        rls = CFMachPortCreateRunLoopSource(NULL, configd_port, 0);
        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, CFSTR("locked"));
        CFRelease(rls);
 
        return;
@@ -293,16 +289,13 @@ __private_extern__
 void
 server_loop()
 {
-       CFStringRef     rlMode;
-
        pthread_setname_np("SCDynamicStore");
 
        while (TRUE) {
                /*
                 * process one run loop event
                 */
-               rlMode = (storeLocked > 0) ? CFSTR("locked") : kCFRunLoopDefaultMode;
-               CFRunLoopRunInMode(rlMode, 1.0e10, TRUE);
+               CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, TRUE);
 
                /*
                 * check for, and if necessary, push out change notifications
index 934c91b49d89817e6d4ca1e00033bf62510abd80..7363bd68dcae76770d14a371fcf582081733116e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2006, 2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -52,7 +52,8 @@ int           server_shutdown (void);
 void           server_loop     (void);
 
 kern_return_t  _snapshot       (mach_port_t            server,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _configopen     (mach_port_t            server,
                                 xmlData_t              nameRef,
@@ -63,22 +64,14 @@ kern_return_t       _configopen     (mach_port_t            server,
                                 int                    *sc_status,
                                 audit_token_t          audit_token);
 
-kern_return_t  _configclose    (mach_port_t            server,
-                                int                    *sc_status);
-
-kern_return_t  _configlock     (mach_port_t            server,
-                                int                    *sc_status);
-
-kern_return_t  _configunlock   (mach_port_t            server,
-                                int                    *sc_status);
-
 kern_return_t  _configlist     (mach_port_t server,
                                 xmlData_t              keyRef,
                                 mach_msg_type_number_t keyLen,
                                 int                    isRegex,
                                 xmlDataOut_t           *listRef,
                                 mach_msg_type_number_t *listLen,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _configadd      (mach_port_t            server,
                                 xmlData_t              keyRef,
@@ -86,7 +79,8 @@ kern_return_t _configadd      (mach_port_t            server,
                                 xmlData_t              dataRef,
                                 mach_msg_type_number_t dataLen,
                                 int                    *newInstance,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _configadd_s    (mach_port_t            server,
                                 xmlData_t              keyRef,
@@ -102,7 +96,8 @@ kern_return_t        _configget      (mach_port_t            server,
                                 xmlDataOut_t           *dataRef,
                                 mach_msg_type_number_t *dataLen,
                                 int                    *newInstance,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _configset      (mach_port_t            server,
                                 xmlData_t              keyRef,
@@ -110,22 +105,20 @@ kern_return_t     _configset      (mach_port_t            server,
                                 xmlData_t              dataRef,
                                 mach_msg_type_number_t dataLen,
                                 int                    *newInstance,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _configremove   (mach_port_t            server,
                                 xmlData_t              keyRef,
                                 mach_msg_type_number_t keyLen,
-                                int                    *sc_status);
-
-kern_return_t  _configtouch    (mach_port_t            server,
-                                xmlData_t              keyRef,
-                                mach_msg_type_number_t keyLen,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _confignotify   (mach_port_t            server,
                                 xmlData_t              keyRef,
                                 mach_msg_type_number_t keyLen,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _configget_m    (mach_port_t            server,
                                 xmlData_t              keysRef,
@@ -134,7 +127,8 @@ kern_return_t       _configget_m    (mach_port_t            server,
                                 mach_msg_type_number_t patternsLen,
                                 xmlDataOut_t           *dataRef,
                                 mach_msg_type_number_t *dataLen,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _configset_m    (mach_port_t            server,
                                 xmlData_t              dataRef,
@@ -143,7 +137,8 @@ kern_return_t       _configset_m    (mach_port_t            server,
                                 mach_msg_type_number_t removeLen,
                                 xmlData_t              notifyRef,
                                 mach_msg_type_number_t notifyLen,
-                                int                    *sc_status);
+                                int                    *sc_status,
+                                audit_token_t          audit_token);
 
 kern_return_t  _notifyadd      (mach_port_t            server,
                                 xmlData_t              keyRef,
index 9309ae13edc341ab5e60b37b54a772dc672ba623..5b7d736a8c2262e4e97743f6590a06848b265171 100644 (file)
@@ -5,13 +5,14 @@
        <key>keychain-access-groups</key>
        <array>
                <string>apple</string>
+               <string>com.apple.certificates</string>
                <string>com.apple.identities</string>
        </array>
        <key>com.apple.springboard.launchapplications</key>
        <true/>
-       <key>com.apple.wifi.manager-access</key>
+       <key>com.apple.multitasking.unlimitedassertions</key>
        <true/>
-       <key>com.apple.MobileInternetSharing.allow</key>
+       <key>com.apple.wifi.manager-access</key>
        <true/>
 </dict>
 </plist>
index 58a87be26409e18ab728bba212f6f3c9443be667..f30790316790479c77629f2eac9a782b3edb977b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2004, 2006-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2003, 2004, 2006-2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -199,7 +199,7 @@ patternCompile(CFStringRef pattern, regex_t *preg, CFStringRef *error)
 }
 
 
-static CFMutableArrayRef
+static CF_RETURNS_RETAINED CFMutableArrayRef
 patternCopy(CFStringRef        pattern)
 {
        CFArrayRef      pInfo;
@@ -209,7 +209,7 @@ patternCopy(CFStringRef     pattern)
 }
 
 
-static CFMutableArrayRef
+static CF_RETURNS_RETAINED CFMutableArrayRef
 patternNew(CFStringRef pattern)
 {
        addContext              context;
@@ -224,7 +224,8 @@ patternNew(CFStringRef pattern)
        /* compile the regular expression from the pattern string. */
        pRegex = CFDataCreateMutable(NULL, sizeof(regex_t));
        CFDataSetLength(pRegex, sizeof(regex_t));
-       if (!patternCompile(pattern, (regex_t *)CFDataGetBytePtr(pRegex), &err)) {
+       /* ALIGN: CF aligns to >8 byte boundries */
+       if (!patternCompile(pattern, (regex_t *)(void *)CFDataGetBytePtr(pRegex), &err)) {
                CFRelease(err);
                CFRelease(pRegex);
                CFRelease(pInfo);
@@ -241,7 +242,8 @@ patternNew(CFStringRef pattern)
 
        /* identify/add all existing keys that match the specified pattern */
        context.pInfo = pInfo;
-       context.preg  = (regex_t *)CFDataGetBytePtr(pRegex);
+       /* ALIGN: CF aligns to >8 byte boundries */
+       context.preg  = (regex_t *)(void *)CFDataGetBytePtr(pRegex);
        my_CFDictionaryApplyFunction(storeData,
                                     (CFDictionaryApplierFunction)identifyKeyForPattern,
                                     &context);
@@ -275,7 +277,8 @@ patternCopyMatches(CFStringRef pattern)
                CFDataRef       pRegex;
 
                pRegex = CFArrayGetValueAtIndex(pInfo, 0);
-               regfree((regex_t *)CFDataGetBytePtr(pRegex));
+               /* ALIGN: CF aligns to >8 byte boundries */
+               regfree((regex_t *)(void *)CFDataGetBytePtr(pRegex));
        }
 
        CFArrayReplaceValues(pInfo, CFRangeMake(0, 2), NULL, 0);
@@ -368,7 +371,8 @@ patternRemoveSession(CFStringRef pattern, CFNumberRef sessionNum)
                /* if no other sessions are watching this pattern */
 
                pRegex = CFArrayGetValueAtIndex(pInfo, 0);
-               regfree((regex_t *)CFDataGetBytePtr(pRegex));
+               /* ALIGN: CF aligns to >8 byte boundries */
+               regfree((regex_t *)(void *)CFDataGetBytePtr(pRegex));
                CFDictionaryRemoveValue(patternData, pattern);
        }
 
@@ -400,7 +404,8 @@ addKeyForPattern(const void *key, void *val, void *context)
        }
 
        /* compare new store key to regular expression pattern */
-       preg = (regex_t *)CFDataGetBytePtr(CFArrayGetValueAtIndex(pInfo, 0));
+       /* ALIGN: CF aligns to >8 byte boundries */
+       preg = (regex_t *)(void *)CFDataGetBytePtr(CFArrayGetValueAtIndex(pInfo, 0));
        reError = regexec(preg, str, 0, NULL, 0);
        switch (reError) {
                case 0 : {
index eded4d67180d96fd77b1f9303db54ab545ede52a..309631d5bb18b6a81cb3b7950ee9964dac52aad1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2009, 2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2009, 2011, 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -49,6 +49,7 @@
 #include "configd.h"
 #include "configd_server.h"
 #include <SystemConfiguration/SCDPlugin.h>
+#include "SCNetworkReachabilityInternal.h"
 void   _SCDPluginExecInit();
 
 
@@ -59,11 +60,44 @@ void        _SCDPluginExecInit();
 #define        BUNDLE_DIR_EXTENSION    ".bundle"
 
 
+#define PLUGIN_ALL(p)          CFSTR(p)
+#if    !TARGET_OS_EMBEDDED
+#define PLUGIN_MACOSX(p)       CFSTR(p)
+#define PLUGIN_IOS(p)          NULL
+#else  // !TARGET_OS_EMBEDDED
+#define PLUGIN_MACOSX(p)       NULL
+#define PLUGIN_IOS(p)          CFSTR(p)
+#endif // !TARGET_OS_EMBEDDED
+
+// white-listed (ok-to-load) bundle identifiers
+static const CFStringRef       pluginWhitelist[]       = {
+       PLUGIN_MACOSX("com.apple.SystemConfiguration.Apple80211"),
+       PLUGIN_MACOSX("com.apple.SystemConfiguration.ApplicationFirewall"),
+       PLUGIN_MACOSX("com.apple.SystemConfiguration.Bluetooth"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.EAPOLController"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.IPConfiguration"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.IPMonitor"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.InterfaceNamer"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.KernelEventMonitor"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.LinkConfiguration"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.Logger"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.PPPController"),
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.PreferencesMonitor"),
+#ifdef HAVE_REACHABILITY_SERVER
+       PLUGIN_ALL   ("com.apple.SystemConfiguration.SCNetworkReachability"),
+#endif // HAVE_REACHABILITY_SERVER
+       PLUGIN_MACOSX("com.apple.SystemConfiguration.wwanConfig"),
+       PLUGIN_MACOSX("com.apple.print.notification"),
+};
+#define        N_PLUGIN_WHITELIST      (sizeof(pluginWhitelist) / sizeof(pluginWhitelist[0]))
+
+
 typedef struct {
        CFBundleRef                             bundle;
        Boolean                                 loaded;
        Boolean                                 builtin;
        Boolean                                 enabled;
+       Boolean                                 forced;
        Boolean                                 verbose;
        SCDynamicStoreBundleLoadFunction        load;
        SCDynamicStoreBundleStartFunction       start;
@@ -91,8 +125,9 @@ extern SCDynamicStoreBundlePrimeFunction     prime_KernelEventMonitor;
 extern SCDynamicStoreBundleLoadFunction                load_LinkConfiguration;
 extern SCDynamicStoreBundleLoadFunction                load_PreferencesMonitor;
 extern SCDynamicStoreBundlePrimeFunction       prime_PreferencesMonitor;
-extern SCDynamicStoreBundleLoadFunction                load_NetworkIdentification;
-extern SCDynamicStoreBundlePrimeFunction       prime_NetworkIdentification;
+#ifdef HAVE_REACHABILITY_SERVER
+extern SCDynamicStoreBundleLoadFunction                load_SCNetworkReachability;
+#endif // HAVE_REACHABILITY_SERVER
 
 
 typedef struct {
@@ -134,19 +169,21 @@ static const builtin builtin_plugins[] = {
                NULL
        },
        {
-               CFSTR("com.apple.SystemConfiguration.NetworkIdentification"),
-               &load_NetworkIdentification,
+               CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"),
+               &load_PreferencesMonitor,
                NULL,
-               &prime_NetworkIdentification,
+               &prime_PreferencesMonitor,
                NULL
        },
+#ifdef HAVE_REACHABILITY_SERVER
        {
-               CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"),
-               &load_PreferencesMonitor,
+               CFSTR("com.apple.SystemConfiguration.SCNetworkReachability"),
+               &load_SCNetworkReachability,
+               NULL,
                NULL,
-               &prime_PreferencesMonitor,
                NULL
-       }
+       },
+#endif // HAVE_REACHABILITY_SERVER
 };
 
 
@@ -185,6 +222,7 @@ addBundle(CFBundleRef bundle, Boolean forceEnabled)
        bundleInfo->loaded      = FALSE;
        bundleInfo->builtin     = FALSE;
        bundleInfo->enabled     = TRUE;
+       bundleInfo->forced      = forceEnabled;
        bundleInfo->verbose     = FALSE;
        bundleInfo->load        = NULL;
        bundleInfo->start       = NULL;
@@ -211,16 +249,12 @@ addBundle(CFBundleRef bundle, Boolean forceEnabled)
                }
        }
 
-       if (forceEnabled) {
-               bundleInfo->enabled = TRUE;
-       }
-
        CFArrayAppendValue(allBundles, bundleInfo);
        return;
 }
 
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 shortBundleIdentifier(CFStringRef bundleID)
 {
        CFIndex         len     = CFStringGetLength(bundleID);
@@ -363,6 +397,7 @@ forkBundle(CFBundleRef bundle, CFStringRef bundleID)
 static void
 loadBundle(const void *value, void *context) {
        CFStringRef     bundleID;
+       Boolean         bundleAllowed;
        bundleInfoRef   bundleInfo      = (bundleInfoRef)value;
        Boolean         bundleExclude;
        CFIndex         *nLoaded        = (CFIndex *)context;
@@ -377,26 +412,35 @@ loadBundle(const void *value, void *context) {
 
        shortID = shortBundleIdentifier(bundleID);
 
-       bundleExclude = CFSetContainsValue(_plugins_exclude, bundleID);
-       if (!bundleExclude) {
-               if (shortID != NULL) {
-                       bundleExclude = CFSetContainsValue(_plugins_exclude, shortID);
-               }
+       bundleAllowed = ((CFSetGetCount(_plugins_allowed) == 0)         ||      // if no white-listing
+                        CFSetContainsValue(_plugins_allowed, bundleID) ||      // if [bundleID] white-listed
+                        ((shortID != NULL) &&
+                         CFSetContainsValue(_plugins_allowed, shortID))||      // if [short bundleID] white-listed
+                        bundleInfo->forced                                     // if "testing" plugin
+                       );
+       if (!bundleAllowed) {
+               SCLog(TRUE, LOG_WARNING, CFSTR("skipped %@ (not allowed)"), bundleID);
+               goto done;
        }
 
+       bundleExclude = (CFSetContainsValue(_plugins_exclude, bundleID) ||      // if [bundleID] excluded
+                        ((shortID != NULL) &&
+                         CFSetContainsValue(_plugins_exclude, shortID))        // if [short bundleID] excluded
+                       );
        if (bundleExclude) {
                // sorry, this bundle has been excluded
                SCLog(TRUE, LOG_NOTICE, CFSTR("skipped %@ (excluded)"), bundleID);
                goto done;
        }
 
-       if (!bundleInfo->enabled) {
+       if (!bundleInfo->enabled && !bundleInfo->forced) {
                // sorry, this bundle has not been enabled
                SCLog(TRUE, LOG_INFO, CFSTR("skipped %@ (disabled)"), bundleID);
                goto done;
        }
 
-       if (_plugins_fork) {
+       if (_plugins_fork &&
+           !_SC_CFEqual(bundleID, CFSTR("com.apple.SystemConfiguration.SCNetworkReachability"))) {
                forkBundle(bundleInfo->bundle, bundleID);
                goto done;
        }
@@ -899,11 +943,19 @@ __private_extern__
 void *
 plugin_exec(void *arg)
 {
+       int             i;
        CFIndex         nLoaded         = 0;
 
        /* keep track of bundles */
        allBundles = CFArrayCreateMutable(NULL, 0, NULL);
 
+       /* add white-listed plugins to those we'll allow to be loaded */
+       for (i = 0; i < N_PLUGIN_WHITELIST; i++) {
+               if (pluginWhitelist[i] != NULL) {
+                       CFSetSetValue(_plugins_allowed, pluginWhitelist[i]);
+               }
+       }
+
        /* allow plug-ins to exec child/helper processes */
        _SCDPluginExecInit();
 
@@ -976,6 +1028,39 @@ plugin_exec(void *arg)
                CFRelease(url);
        }
 
+       /*
+        * Look for the InterfaceNamer plugin, and move it to the start
+        * of the list.
+        *
+        * Load the InterfaceNamer plugin (and thereby start its thread)
+        * first in an attempt to minimize the amount of time that
+        * opendirectoryd has to wait for the platform UUID to appear in
+        * nvram.
+        *
+        * InterfaceNamer is responsible for creating the platform UUID on
+        * platforms without a UUID in ROM. Until the platform UUID is created
+        * and stashed in nvram, all calls to opendirectoryd to do things like
+        * getpwuid() will block, because opendirectoryd will block while trying
+        * to read the platform UUID from the kernel.
+        *
+        * As an example, dlopen() causes XPC to do some intialization, and
+        * part of that initialization involves communicating with xpcd.
+        * Since xpcd calls getpwuid_r() during its initialization, it will
+        * block until the platform UUID is available.
+        */
+       for (int i = 0; i < CFArrayGetCount(allBundles); i++) {
+               bundleInfoRef   bi              = (bundleInfoRef)CFArrayGetValueAtIndex(allBundles, i);
+               CFStringRef     bundleID        = CFBundleGetIdentifier(bi->bundle);
+
+               if (_SC_CFEqual(bundleID,
+                               CFSTR("com.apple.SystemConfiguration.InterfaceNamer")))
+               {
+                       CFArrayRemoveValueAtIndex(allBundles, i);
+                       CFArrayInsertValueAtIndex(allBundles, 0, bi);
+                       break;
+               }
+       }
+
 #ifdef DEBUG
        traceBundle("before loading any plugins", NULL);
 #endif /* DEBUG */
index 1b77827040a48d70aff979cf91a03ef553759075..cbb5b961c77a2df59e162b03a9934df8fbbff7e1 100644 (file)
 
 
 /* information maintained for each active session */
-static serverSessionRef        *sessions = NULL;
-static int             nSessions = 0;
+static serverSessionRef        *sessions       = NULL;
+static int             nSessions       = 0;    /* # of allocated sessions */
+static int             lastSession     = -1;   /* # of last used session */
 
 /* CFMachPortInvalidation runloop */
 static CFRunLoopRef    sessionRunLoop  = NULL;
 
+/* temp session */
+static serverSessionRef        temp_session    = NULL;
+
 
 static void
 CFMachPortInvalidateSessionCallback(CFMachPortRef port, void *info)
@@ -73,16 +77,23 @@ getSession(mach_port_t server)
                return NULL;
        }
 
-       for (i = 0; i < nSessions; i++) {
+       /* look for matching session (note: slot 0 is the "server" port) */
+       for (i = 1; i <= lastSession; i++) {
                serverSessionRef        thisSession = sessions[i];
 
                if (thisSession == NULL) {
                        /* found an empty slot, skip it */
                        continue;
-               } else if (thisSession->key == server) {
-                       return thisSession;     /* we've seen this server before */
-               } else if (thisSession->store &&
-                          (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) {
+               }
+
+               if (thisSession->key == server) {
+                       /* we've seen this server before */
+                       return thisSession;
+               }
+
+               if ((thisSession->store != NULL) &&
+                   (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) {
+                       /* we've seen this task port before */
                        return thisSession;
                }
        }
@@ -92,6 +103,38 @@ getSession(mach_port_t server)
 }
 
 
+__private_extern__
+serverSessionRef
+tempSession(mach_port_t server, CFStringRef name, audit_token_t auditToken)
+{
+       static dispatch_once_t          once;
+       SCDynamicStorePrivateRef        storePrivate;
+
+       if (sessions[0]->key != server) {
+               // if not SCDynamicStore "server" port
+               return NULL;
+       }
+
+       dispatch_once(&once, ^{
+               temp_session = sessions[0];     /* use "server" session */
+               (void) __SCDynamicStoreOpen(&temp_session->store, NULL);
+       });
+
+       /* save audit token */
+       temp_session->auditToken        = auditToken;
+       temp_session->callerEUID        = -1;           /* not "root" */
+       temp_session->callerRootAccess  = UNKNOWN;
+       temp_session->callerWriteAccess = UNKNOWN;
+
+       /* save name */
+       storePrivate = (SCDynamicStorePrivateRef)temp_session->store;
+       if (storePrivate->name != NULL) CFRelease(storePrivate->name);
+       storePrivate->name = CFRetain(name);
+
+       return temp_session;
+}
+
+
 __private_extern__
 serverSessionRef
 addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info))
@@ -106,26 +149,58 @@ addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info))
        }
 
        if (nSessions <= 0) {
-               /* new session (actually, the first) found */
-               sessions = malloc(sizeof(serverSessionRef));
-               n = 0;
-               nSessions = 1;
+               /* if first session (the "server" port) */
+               n = 0;          /* use slot "0" */
+               lastSession = 0;        /* last used slot */
+
+               nSessions = 64;
+               sessions = malloc(nSessions * sizeof(serverSessionRef));
        } else {
                int     i;
 
-               for (i = 0; i < nSessions; i++) {
-                       if (sessions[i] == NULL) {
-                               /* found an empty slot, use it */
-                               n = i;
-                               break;
+               /* check to see if we already have an open session (note: slot 0 is the "server" port) */
+               for (i = 1; i <= lastSession; i++) {
+                       serverSessionRef        thisSession = sessions[i];
+
+                       if (thisSession == NULL) {
+                               /* found an empty slot */
+                               if (n < 0) {
+                                       /* keep track of the first [empty] slot */
+                                       n = i;
+                               }
+
+                               /* and keep looking for a matching session */
+                               continue;
+                       }
+
+                       if (thisSession->key == server) {
+                               /* we've seen this server before */
+                               return NULL;
+                       }
+
+                       if ((thisSession->store != NULL) &&
+                                  (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) {
+                               /* we've seen this task port before */
+                               return NULL;
                        }
                }
-               /* new session identified */
+
+               /* add a new session */
                if (n < 0) {
-                       /* no empty slots, add one to the list */
-                       n = nSessions++;
-                       sessions = reallocf(sessions, ((nSessions) * sizeof(serverSessionRef)));
+                       /* if no empty slots */
+                       n = ++lastSession;
+                       if (lastSession >= nSessions) {
+                               /* expand the session list */
+                               nSessions *= 2;
+                               sessions = reallocf(sessions, (nSessions * sizeof(serverSessionRef)));
+                       }
                }
+
+               // create mach port for SCDynamicStore client
+               mp = MACH_PORT_NULL;
+               (void) mach_port_allocate(mach_task_self(),
+                                         MACH_PORT_RIGHT_RECEIVE,
+                                         &mp);
        }
 
        // allocate a new session for this server
@@ -133,15 +208,8 @@ addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info))
        bzero(sessions[n], sizeof(serverSession));
 
        // create server port
-       context.info            = sessions[n];
-       context.copyDescription = copyDescription;
-
-       if (server == MACH_PORT_NULL) {
-               // create mach port for SCDynamicStore client
-               (void) mach_port_allocate(mach_task_self(),
-                                         MACH_PORT_RIGHT_RECEIVE,
-                                         &mp);
-       }
+       context.info             = sessions[n];
+       context.copyDescription = copyDescription;
 
        //
        // Note: we create the CFMachPort *before* we insert a send
@@ -160,7 +228,7 @@ addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info))
        CFMachPortSetInvalidationCallBack(sessions[n]->serverPort,
                                          CFMachPortInvalidateSessionCallback);
 
-       if (server == MACH_PORT_NULL) {
+       if (n > 0) {
                // insert send right that will be moved to the client
                (void) mach_port_insert_right(mach_task_self(),
                                              mp,
@@ -181,51 +249,20 @@ addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info))
 
 __private_extern__
 void
-removeSession(mach_port_t server)
+cleanupSession(mach_port_t server)
 {
-       int                     i;
-       serverSessionRef        thisSession;
-       CFStringRef             sessionKey;
+       int             i;
 
-       for (i = 0; i < nSessions; i++) {
-               thisSession = sessions[i];
+       for (i = 1; i <= lastSession; i++) {
+               CFStringRef             sessionKey;
+               serverSessionRef        thisSession = sessions[i];
 
                if (thisSession == NULL) {
                        /* found an empty slot, skip it */
                        continue;
-               } else if (thisSession->key == server) {
-                       /*
-                        * We don't need any remaining information in the
-                        * sessionData dictionary, remove it.
-                        */
-                       sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), server);
-                       CFDictionaryRemoveValue(sessionData, sessionKey);
-                       CFRelease(sessionKey);
-
-                       /*
-                        * Lastly, get rid of the per-session structure.
-                        */
-                       free(thisSession);
-                       sessions[i] = NULL;
-
-                       return;
                }
-       }
-
-       return;
-}
-
-
-__private_extern__
-void
-cleanupSession(mach_port_t server)
-{
-       int             i;
 
-       for (i = 0; i < nSessions; i++) {
-               serverSessionRef        thisSession = sessions[i];
-
-               if ((thisSession != NULL) && (thisSession->key == server)) {
+               if (thisSession->key == server) {
                        /*
                         * session entry still exists.
                         */
@@ -234,26 +271,12 @@ cleanupSession(mach_port_t server)
                                SCTrace(TRUE, _configd_trace, CFSTR("cleanup : %5d\n"), server);
                        }
 
-                       /*
-                        * Ensure that any changes made while we held the "lock"
-                        * are discarded.
-                        */
-                       if ((storeLocked > 0) &&
-                           ((SCDynamicStorePrivateRef)thisSession->store)->locked) {
-                               /*
-                                * swap store and associated data which, after
-                                * being closed, will result in the restoration
-                                * of the original pre-"locked" data.
-                                */
-                               _swapLockedStoreData();
-                       }
-
                        /*
                         * Close any open connections including cancelling any outstanding
                         * notification requests and releasing any locks.
                         */
                        __MACH_PORT_DEBUG(TRUE, "*** cleanupSession", server);
-                       (void) __SCDynamicStoreClose(&thisSession->store, TRUE);
+                       (void) __SCDynamicStoreClose(&thisSession->store);
                        __MACH_PORT_DEBUG(TRUE, "*** cleanupSession (after __SCDynamicStoreClose)", server);
 
                        /*
@@ -262,9 +285,27 @@ cleanupSession(mach_port_t server)
                        (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1);
 
                        /*
-                        * Lastly, remove the session entry.
+                        * We don't need any remaining information in the
+                        * sessionData dictionary, remove it.
+                        */
+                       sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), server);
+                       CFDictionaryRemoveValue(sessionData, sessionKey);
+                       CFRelease(sessionKey);
+
+                       /*
+                        * get rid of the per-session structure.
                         */
-                       removeSession(server);
+                       free(thisSession);
+                       sessions[i] = NULL;
+
+                       if (i == lastSession) {
+                               /* we are removing the last session, update last used slot */
+                               while (--lastSession > 0) {
+                                       if (sessions[lastSession] != NULL) {
+                                               break;
+                                       }
+                               }
+                       }
 
                        return;
                }
@@ -283,7 +324,7 @@ listSessions(FILE *f)
        int     i;
 
        SCPrint(TRUE, f, CFSTR("Current sessions :\n"));
-       for (i = 0; i < nSessions; i++) {
+       for (i = 0; i <= lastSession; i++) {
                serverSessionRef        thisSession = sessions[i];
 
                if (thisSession == NULL) {
index 6e4962f43eb0e341e4531b220a0a77bedfd6998b..68d8f910ad322887126cff19259454f95a8d4dfd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2005-2007, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2005-2007, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -78,11 +78,13 @@ __BEGIN_DECLS
 
 serverSessionRef       getSession      (mach_port_t    server);
 
+serverSessionRef       tempSession     (mach_port_t    server,
+                                        CFStringRef    name,
+                                        audit_token_t  auditToken);
+
 serverSessionRef       addSession      (mach_port_t    server,
                                         CFStringRef    (*copyDescription)(const void *info));
 
-void                   removeSession   (mach_port_t    server);
-
 void                   cleanupSession  (mach_port_t    server);
 
 void                   listSessions    (FILE           *f);
index b572e25d40e4305e85c118b86f49d9b7948c086b..ebce9e4d5fefa75cf28bcd48047ddafcdfd94b9b 100644 (file)
@@ -3,7 +3,7 @@
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 45;
+       objectVersion = 46;
        objects = {
 
 /* Begin PBXAggregateTarget section */
@@ -41,6 +41,7 @@
                                1558480607550D470046C2E9 /* PBXTargetDependency */,
                                1558480807550D470046C2E9 /* PBXTargetDependency */,
                                1558480A07550D470046C2E9 /* PBXTargetDependency */,
+                               D6DDAC3D147A24BC00A2E902 /* PBXTargetDependency */,
                                150ECB300D0042DA0065E94D /* PBXTargetDependency */,
                        );
                        name = configd_executables;
@@ -53,7 +54,6 @@
                        );
                        dependencies = (
                                157BB8C0075924460025DA7A /* PBXTargetDependency */,
-                               1520A386084681350010B584 /* PBXTargetDependency */,
                        );
                        name = configd_base;
                        productName = Frameworks;
                        buildPhases = (
                        );
                        dependencies = (
-                               157A85480D56CA0B00B6F1A0 /* PBXTargetDependency */,
-                               158317BB0CFB8660006F62B9 /* PBXTargetDependency */,
                                157A854A0D56CA2300B6F1A0 /* PBXTargetDependency */,
                                158317B90CFB8660006F62B9 /* PBXTargetDependency */,
+                               157A85480D56CA0B00B6F1A0 /* PBXTargetDependency */,
+                               158317BB0CFB8660006F62B9 /* PBXTargetDependency */,
                                157A854C0D56CA5100B6F1A0 /* PBXTargetDependency */,
                                158317B70CFB8660006F62B9 /* PBXTargetDependency */,
                                157A854E0D56CA6F00B6F1A0 /* PBXTargetDependency */,
                                158317B50CFB8660006F62B9 /* PBXTargetDependency */,
                                156CA4A80EF8550800C59A18 /* PBXTargetDependency */,
-                               157A85500D56CA8800B6F1A0 /* PBXTargetDependency */,
-                               158317B30CFB8660006F62B9 /* PBXTargetDependency */,
                                157A85520D56CA9E00B6F1A0 /* PBXTargetDependency */,
                                157A85540D56CACA00B6F1A0 /* PBXTargetDependency */,
+                               1528C00F135741C300691881 /* PBXTargetDependency */,
+                               1528C011135741C300691881 /* PBXTargetDependency */,
                        );
                        name = "configd_plugins-Embedded";
                        productName = Plugins;
                        buildPhases = (
                        );
                        dependencies = (
-                               15AC5189108396D2004A9ED5 /* PBXTargetDependency */,
-                               15AC5187108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC5185108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC5183108396D2004A9ED5 /* PBXTargetDependency */,
+                               15AC5189108396D2004A9ED5 /* PBXTargetDependency */,
+                               15AC5187108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC5181108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC517F108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC517D108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC517B108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC5179108396D2004A9ED5 /* PBXTargetDependency */,
-                               15AC5177108396D2004A9ED5 /* PBXTargetDependency */,
-                               15AC5175108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC5173108396D2004A9ED5 /* PBXTargetDependency */,
                                15AC5171108396D2004A9ED5 /* PBXTargetDependency */,
+                               1528C0131357420300691881 /* PBXTargetDependency */,
+                               1528C0151357420300691881 /* PBXTargetDependency */,
                        );
                        name = "configd_plugins-EmbeddedOther";
                        productName = Plugins;
                        buildPhases = (
                        );
                        dependencies = (
-                               159D542807528E85004F8947 /* PBXTargetDependency */,
-                               158AD9860754E72500124717 /* PBXTargetDependency */,
-                               159D542607528E85004F8947 /* PBXTargetDependency */,
-                               158AD9880754E72500124717 /* PBXTargetDependency */,
                                15828B070753B77E00AD4710 /* PBXTargetDependency */,
                                159D542207528E85004F8947 /* PBXTargetDependency */,
+                               159D542607528E85004F8947 /* PBXTargetDependency */,
+                               158AD9880754E72500124717 /* PBXTargetDependency */,
+                               159D542807528E85004F8947 /* PBXTargetDependency */,
+                               158AD9860754E72500124717 /* PBXTargetDependency */,
                                159D542A07528E85004F8947 /* PBXTargetDependency */,
                                158AD98C0754E72500124717 /* PBXTargetDependency */,
                                1521405B0E9400BF00DACD2C /* PBXTargetDependency */,
                                159D542C07528E85004F8947 /* PBXTargetDependency */,
                                158AD98E0754E72500124717 /* PBXTargetDependency */,
-                               F95B8A790B03FB9100993BA3 /* PBXTargetDependency */,
-                               F95B8A770B03FB9100993BA3 /* PBXTargetDependency */,
+                               1528BFEC135731B800691881 /* PBXTargetDependency */,
+                               1528BFEE135731B800691881 /* PBXTargetDependency */,
                        );
                        name = configd_plugins;
                        productName = Plugins;
                15060818075A00A300B147BA /* SCSchemaDefinitions.c in Sources */ = {isa = PBXBuildFile; fileRef = 150607BD075A00A200B147BA /* SCSchemaDefinitions.c */; };
                1506081A075A00A300B147BA /* SCSchemaDefinitions.h in Headers */ = {isa = PBXBuildFile; fileRef = 150607DE075A00A300B147BA /* SCSchemaDefinitions.h */; settings = {ATTRIBUTES = (Public, ); }; };
                150D7E1E0D16DC6C00AF4BED /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1520A3DE0846B2DC0010B584 /* Security.framework */; };
+               151E0CA31378EE1000C5DA2A /* network_information.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A781368913C0091C931 /* network_information.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               151E0CA51378EE3B00C5DA2A /* network_information.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A77136891300091C931 /* network_information.c */; };
                1520A3870846829A0010B584 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */; };
                1520A3DF0846B2DD0010B584 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1520A3DE0846B2DC0010B584 /* Security.framework */; };
                152140020E93EC6500DACD2C /* logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 1531D3DB0E93E6DA00248432 /* logger.c */; };
                1521400C0E93FFF500DACD2C /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */; };
                152140580E93FFFC00DACD2C /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1559C4440D349A4E0098FD59 /* SystemConfiguration.framework */; };
                1522FCFB0FA7FE4B00B24128 /* dnsinfo_flatfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 1522FCE50FA7FD7000B24128 /* dnsinfo_flatfile.c */; };
-               152691D81129EE8A006BD2D5 /* BondConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 9EE943F306AF409B00772EB5 /* BondConfiguration.c */; };
-               152691D91129EE94006BD2D5 /* BondConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 9EE943F306AF409B00772EB5 /* BondConfiguration.c */; };
-               152691DA1129EE98006BD2D5 /* BondConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 9EE943F306AF409B00772EB5 /* BondConfiguration.c */; };
                152691DB1129EEA6006BD2D5 /* BridgeConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FD7B3B101E439200C56621 /* BridgeConfiguration.c */; };
                152691DC1129EEAD006BD2D5 /* BridgeConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FD7B3B101E439200C56621 /* BridgeConfiguration.c */; };
                152691DD1129EEB1006BD2D5 /* BridgeConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FD7B3B101E439200C56621 /* BridgeConfiguration.c */; };
                152691DE1129EEC2006BD2D5 /* VLANConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69B605C0722B0099E85F /* VLANConfiguration.c */; };
                152691DF1129EEC8006BD2D5 /* VLANConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69B605C0722B0099E85F /* VLANConfiguration.c */; };
                152691E01129EECB006BD2D5 /* VLANConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69B605C0722B0099E85F /* VLANConfiguration.c */; };
+               1528BFEF135733F500691881 /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; };
+               1528BFF313573FEE00691881 /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; };
+               1528C0021357401900691881 /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; };
+               1528C0171357465900691881 /* libSCNetworkReachability.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1528BFF713573FEE00691881 /* libSCNetworkReachability.a */; };
+               1528C019135746BB00691881 /* libSCNetworkReachability.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1528BFE21357305400691881 /* libSCNetworkReachability.a */; };
+               1528C01A135746D700691881 /* libSCNetworkReachability.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1528C0061357401900691881 /* libSCNetworkReachability.a */; };
                152E0E7F10FE820E00E402F2 /* helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 152E0E7E10FE820E00E402F2 /* helper.defs */; settings = {ATTRIBUTES = (Server, ); }; };
                152E0E8010FE820E00E402F2 /* helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 152E0E7E10FE820E00E402F2 /* helper.defs */; settings = {ATTRIBUTES = (Server, ); }; };
                152E0E8110FE820E00E402F2 /* helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 152E0E7E10FE820E00E402F2 /* helper.defs */; settings = {ATTRIBUTES = (Server, ); }; };
                152E0E8B10FE824000E402F2 /* helper_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 152E0E8810FE824000E402F2 /* helper_types.h */; };
                152E68C10A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 152E68C00A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                152E68C30A2C89E30011FDA8 /* SCPreferencesKeychainPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 152E68C20A2C89E30011FDA8 /* SCPreferencesKeychainPrivate.c */; };
-               1533D77B0B10A14300CA4946 /* libNetworkIdentification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */; };
                1540E3610987DA9500157C07 /* com.apple.configd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1540E3600987DA9500157C07 /* com.apple.configd.plist */; };
                154361E00752C81800A8EC6C /* set-hostname.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53AB07528B36004F8947 /* set-hostname.c */; };
                1543636B0752D03C00A8EC6C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1543636A0752D03C00A8EC6C /* IOKit.framework */; };
                1572C4E20CFB55B400E2776E /* SCDPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695405C0722B0099E85F /* SCDPrivate.c */; settings = {ATTRIBUTES = (); }; };
                1572C4E30CFB55B400E2776E /* SCDPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695605C0722B0099E85F /* SCDPlugin.c */; settings = {ATTRIBUTES = (); }; };
                1572C4E40CFB55B400E2776E /* SCDOpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695805C0722B0099E85F /* SCDOpen.c */; settings = {ATTRIBUTES = (); }; };
-               1572C4E50CFB55B400E2776E /* SCDLock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695A05C0722B0099E85F /* SCDLock.c */; settings = {ATTRIBUTES = (); }; };
-               1572C4E60CFB55B400E2776E /* SCDUnlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695C05C0722B0099E85F /* SCDUnlock.c */; settings = {ATTRIBUTES = (); }; };
                1572C4E70CFB55B400E2776E /* SCDList.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695E05C0722B0099E85F /* SCDList.c */; settings = {ATTRIBUTES = (); }; };
                1572C4E80CFB55B400E2776E /* SCDAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696005C0722B0099E85F /* SCDAdd.c */; settings = {ATTRIBUTES = (); }; };
                1572C4E90CFB55B400E2776E /* SCDGet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696405C0722B0099E85F /* SCDGet.c */; settings = {ATTRIBUTES = (); }; };
                1572C4EA0CFB55B400E2776E /* SCDSet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696605C0722B0099E85F /* SCDSet.c */; settings = {ATTRIBUTES = (); }; };
                1572C4EB0CFB55B400E2776E /* SCDRemove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696805C0722B0099E85F /* SCDRemove.c */; settings = {ATTRIBUTES = (); }; };
-               1572C4EC0CFB55B400E2776E /* SCDTouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696A05C0722B0099E85F /* SCDTouch.c */; settings = {ATTRIBUTES = (); }; };
                1572C4ED0CFB55B400E2776E /* SCDNotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696C05C0722B0099E85F /* SCDNotify.c */; settings = {ATTRIBUTES = (); }; };
                1572C4EE0CFB55B400E2776E /* SCDNotifierSetKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */; settings = {ATTRIBUTES = (); }; };
                1572C4EF0CFB55B400E2776E /* SCDNotifierAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */; settings = {ATTRIBUTES = (); }; };
                1572C4F10CFB55B400E2776E /* SCDNotifierGetChanges.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */; settings = {ATTRIBUTES = (); }; };
                1572C4F20CFB55B400E2776E /* SCDNotifierWait.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697605C0722B0099E85F /* SCDNotifierWait.c */; settings = {ATTRIBUTES = (); }; };
                1572C4F30CFB55B400E2776E /* SCDNotifierInformViaCallback.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */; settings = {ATTRIBUTES = (); }; };
-               1572C4F40CFB55B400E2776E /* SCDNotifierInformViaMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */; settings = {ATTRIBUTES = (); }; };
                1572C4F50CFB55B400E2776E /* SCDNotifierInformViaFD.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */; settings = {ATTRIBUTES = (); }; };
                1572C4F60CFB55B400E2776E /* SCDNotifierInformViaSignal.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */; settings = {ATTRIBUTES = (); }; };
                1572C4F70CFB55B400E2776E /* SCDNotifierCancel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */; settings = {ATTRIBUTES = (); }; };
                157A851D0D56C8E000B6F1A0 /* ev_ipv6.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53B407528B36004F8947 /* ev_ipv6.c */; };
                157A851E0D56C8E000B6F1A0 /* eventmon.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53B007528B36004F8947 /* eventmon.c */; };
                157A85290D56C91100B6F1A0 /* linkconfig.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53C107528B36004F8947 /* linkconfig.c */; };
-               157A85340D56C94F00B6F1A0 /* NetworkIdentification.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A680B03F97800993BA3 /* NetworkIdentification.c */; };
                157A853F0D56C96F00B6F1A0 /* prefsmon.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53C307528B36004F8947 /* prefsmon.c */; };
                157A88890A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 157A88880A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                158317250CFB80A1006F62B9 /* configd.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69CF05C0722B0099E85F /* configd.h */; };
                158317330CFB80A1006F62B9 /* pattern.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69EC05C0722B0099E85F /* pattern.c */; settings = {ATTRIBUTES = (); }; };
                158317340CFB80A1006F62B9 /* _configopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F005C0722B0099E85F /* _configopen.c */; settings = {ATTRIBUTES = (); }; };
                158317350CFB80A1006F62B9 /* _configclose.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F205C0722B0099E85F /* _configclose.c */; settings = {ATTRIBUTES = (); }; };
-               158317360CFB80A1006F62B9 /* _configlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F405C0722B0099E85F /* _configlock.c */; settings = {ATTRIBUTES = (); }; };
                158317370CFB80A1006F62B9 /* _configunlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F605C0722B0099E85F /* _configunlock.c */; settings = {ATTRIBUTES = (); }; };
                158317380CFB80A1006F62B9 /* _configlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F805C0722B0099E85F /* _configlist.c */; settings = {ATTRIBUTES = (); }; };
                158317390CFB80A1006F62B9 /* _configadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FA05C0722B0099E85F /* _configadd.c */; settings = {ATTRIBUTES = (); }; };
                1583173A0CFB80A1006F62B9 /* _configget.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FE05C0722B0099E85F /* _configget.c */; settings = {ATTRIBUTES = (); }; };
                1583173B0CFB80A1006F62B9 /* _configset.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0005C0722B0099E85F /* _configset.c */; settings = {ATTRIBUTES = (); }; };
                1583173C0CFB80A1006F62B9 /* _configremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0205C0722B0099E85F /* _configremove.c */; settings = {ATTRIBUTES = (); }; };
-               1583173D0CFB80A1006F62B9 /* _configtouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0405C0722B0099E85F /* _configtouch.c */; settings = {ATTRIBUTES = (); }; };
                1583173E0CFB80A1006F62B9 /* _confignotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0605C0722B0099E85F /* _confignotify.c */; settings = {ATTRIBUTES = (); }; };
                1583173F0CFB80A1006F62B9 /* _notifyadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0805C0722B0099E85F /* _notifyadd.c */; settings = {ATTRIBUTES = (); }; };
                158317400CFB80A1006F62B9 /* _notifyremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0A05C0722B0099E85F /* _notifyremove.c */; settings = {ATTRIBUTES = (); }; };
                158317530CFB80A1006F62B9 /* libInterfaceNamer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53E507528C4A004F8947 /* libInterfaceNamer.a */; };
                158317540CFB80A1006F62B9 /* libIPMonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53EC07528C61004F8947 /* libIPMonitor.a */; };
                158317550CFB80A1006F62B9 /* libLinkConfiguration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53F307528C79004F8947 /* libLinkConfiguration.a */; };
-               158317560CFB80A1006F62B9 /* libNetworkIdentification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */; };
                158317570CFB80A1006F62B9 /* libPreferencesMonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53FA07528C95004F8947 /* libPreferencesMonitor.a */; };
                1583175C0CFB80A1006F62B9 /* com.apple.configd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1540E3600987DA9500157C07 /* com.apple.configd.plist */; };
                1583379C0CFB6B9E0033AB93 /* SCHelper_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 155B7BF60847776D00F0E262 /* SCHelper_client.h */; };
                1583EA53108395BB00A3BC0C /* SCDPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695405C0722B0099E85F /* SCDPrivate.c */; settings = {ATTRIBUTES = (); }; };
                1583EA54108395BB00A3BC0C /* SCDPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695605C0722B0099E85F /* SCDPlugin.c */; settings = {ATTRIBUTES = (); }; };
                1583EA55108395BB00A3BC0C /* SCDOpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695805C0722B0099E85F /* SCDOpen.c */; settings = {ATTRIBUTES = (); }; };
-               1583EA56108395BB00A3BC0C /* SCDLock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695A05C0722B0099E85F /* SCDLock.c */; settings = {ATTRIBUTES = (); }; };
-               1583EA57108395BB00A3BC0C /* SCDUnlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695C05C0722B0099E85F /* SCDUnlock.c */; settings = {ATTRIBUTES = (); }; };
                1583EA58108395BB00A3BC0C /* SCDList.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695E05C0722B0099E85F /* SCDList.c */; settings = {ATTRIBUTES = (); }; };
                1583EA59108395BB00A3BC0C /* SCDAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696005C0722B0099E85F /* SCDAdd.c */; settings = {ATTRIBUTES = (); }; };
                1583EA5A108395BB00A3BC0C /* SCDGet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696405C0722B0099E85F /* SCDGet.c */; settings = {ATTRIBUTES = (); }; };
                1583EA5B108395BB00A3BC0C /* SCDSet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696605C0722B0099E85F /* SCDSet.c */; settings = {ATTRIBUTES = (); }; };
                1583EA5C108395BB00A3BC0C /* SCDRemove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696805C0722B0099E85F /* SCDRemove.c */; settings = {ATTRIBUTES = (); }; };
-               1583EA5D108395BB00A3BC0C /* SCDTouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696A05C0722B0099E85F /* SCDTouch.c */; settings = {ATTRIBUTES = (); }; };
                1583EA5E108395BB00A3BC0C /* SCDNotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696C05C0722B0099E85F /* SCDNotify.c */; settings = {ATTRIBUTES = (); }; };
                1583EA5F108395BB00A3BC0C /* SCDNotifierSetKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */; settings = {ATTRIBUTES = (); }; };
                1583EA60108395BB00A3BC0C /* SCDNotifierAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */; settings = {ATTRIBUTES = (); }; };
                1583EA62108395BB00A3BC0C /* SCDNotifierGetChanges.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */; settings = {ATTRIBUTES = (); }; };
                1583EA63108395BB00A3BC0C /* SCDNotifierWait.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697605C0722B0099E85F /* SCDNotifierWait.c */; settings = {ATTRIBUTES = (); }; };
                1583EA64108395BB00A3BC0C /* SCDNotifierInformViaCallback.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */; settings = {ATTRIBUTES = (); }; };
-               1583EA65108395BB00A3BC0C /* SCDNotifierInformViaMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */; settings = {ATTRIBUTES = (); }; };
                1583EA66108395BB00A3BC0C /* SCDNotifierInformViaFD.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */; settings = {ATTRIBUTES = (); }; };
                1583EA67108395BB00A3BC0C /* SCDNotifierInformViaSignal.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */; settings = {ATTRIBUTES = (); }; };
                1583EA68108395BB00A3BC0C /* SCDNotifierCancel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */; settings = {ATTRIBUTES = (); }; };
                1583EB1A108395BC00A3BC0C /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */; };
                1583EB1B108395BC00A3BC0C /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1559C4440D349A4E0098FD59 /* SystemConfiguration.framework */; };
                1583EB1C108395BC00A3BC0C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1543636A0752D03C00A8EC6C /* IOKit.framework */; };
-               1583EB26108395BD00A3BC0C /* NetworkIdentification.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A680B03F97800993BA3 /* NetworkIdentification.c */; };
                1583EB35108395BD00A3BC0C /* prefsmon.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53C307528B36004F8947 /* prefsmon.c */; };
                1583EB4D108395BD00A3BC0C /* configd.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69CF05C0722B0099E85F /* configd.h */; };
                1583EB4E108395BD00A3BC0C /* _SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69D105C0722B0099E85F /* _SCD.h */; };
                1583EB5B108395BD00A3BC0C /* pattern.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69EC05C0722B0099E85F /* pattern.c */; settings = {ATTRIBUTES = (); }; };
                1583EB5C108395BD00A3BC0C /* _configopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F005C0722B0099E85F /* _configopen.c */; settings = {ATTRIBUTES = (); }; };
                1583EB5D108395BD00A3BC0C /* _configclose.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F205C0722B0099E85F /* _configclose.c */; settings = {ATTRIBUTES = (); }; };
-               1583EB5E108395BD00A3BC0C /* _configlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F405C0722B0099E85F /* _configlock.c */; settings = {ATTRIBUTES = (); }; };
                1583EB5F108395BD00A3BC0C /* _configunlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F605C0722B0099E85F /* _configunlock.c */; settings = {ATTRIBUTES = (); }; };
                1583EB60108395BD00A3BC0C /* _configlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F805C0722B0099E85F /* _configlist.c */; settings = {ATTRIBUTES = (); }; };
                1583EB61108395BD00A3BC0C /* _configadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FA05C0722B0099E85F /* _configadd.c */; settings = {ATTRIBUTES = (); }; };
                1583EB62108395BD00A3BC0C /* _configget.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FE05C0722B0099E85F /* _configget.c */; settings = {ATTRIBUTES = (); }; };
                1583EB63108395BD00A3BC0C /* _configset.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0005C0722B0099E85F /* _configset.c */; settings = {ATTRIBUTES = (); }; };
                1583EB64108395BD00A3BC0C /* _configremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0205C0722B0099E85F /* _configremove.c */; settings = {ATTRIBUTES = (); }; };
-               1583EB65108395BD00A3BC0C /* _configtouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0405C0722B0099E85F /* _configtouch.c */; settings = {ATTRIBUTES = (); }; };
                1583EB66108395BD00A3BC0C /* _confignotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0605C0722B0099E85F /* _confignotify.c */; settings = {ATTRIBUTES = (); }; };
                1583EB67108395BD00A3BC0C /* _notifyadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0805C0722B0099E85F /* _notifyadd.c */; settings = {ATTRIBUTES = (); }; };
                1583EB68108395BD00A3BC0C /* _notifyremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0A05C0722B0099E85F /* _notifyremove.c */; settings = {ATTRIBUTES = (); }; };
                1583EB7A108395BD00A3BC0C /* libInterfaceNamer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53E507528C4A004F8947 /* libInterfaceNamer.a */; };
                1583EB7B108395BD00A3BC0C /* libIPMonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53EC07528C61004F8947 /* libIPMonitor.a */; };
                1583EB7C108395BD00A3BC0C /* libLinkConfiguration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53F307528C79004F8947 /* libLinkConfiguration.a */; };
-               1583EB7D108395BD00A3BC0C /* libNetworkIdentification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */; };
                1583EB7E108395BD00A3BC0C /* libPreferencesMonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53FA07528C95004F8947 /* libPreferencesMonitor.a */; };
                1583EB80108395BD00A3BC0C /* com.apple.configd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1540E3600987DA9500157C07 /* com.apple.configd.plist */; };
                1583EB89108395BE00A3BC0C /* scselect.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A2E05C0722B0099E85F /* scselect.c */; settings = {ATTRIBUTES = (); }; };
                159D54B207529FFF004F8947 /* pattern.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69EC05C0722B0099E85F /* pattern.c */; settings = {ATTRIBUTES = (); }; };
                159D54B307529FFF004F8947 /* _configopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F005C0722B0099E85F /* _configopen.c */; settings = {ATTRIBUTES = (); }; };
                159D54B407529FFF004F8947 /* _configclose.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F205C0722B0099E85F /* _configclose.c */; settings = {ATTRIBUTES = (); }; };
-               159D54B507529FFF004F8947 /* _configlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F405C0722B0099E85F /* _configlock.c */; settings = {ATTRIBUTES = (); }; };
                159D54B607529FFF004F8947 /* _configunlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F605C0722B0099E85F /* _configunlock.c */; settings = {ATTRIBUTES = (); }; };
                159D54B707529FFF004F8947 /* _configlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F805C0722B0099E85F /* _configlist.c */; settings = {ATTRIBUTES = (); }; };
                159D54B807529FFF004F8947 /* _configadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FA05C0722B0099E85F /* _configadd.c */; settings = {ATTRIBUTES = (); }; };
                159D54B907529FFF004F8947 /* _configget.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FE05C0722B0099E85F /* _configget.c */; settings = {ATTRIBUTES = (); }; };
                159D54BA07529FFF004F8947 /* _configset.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0005C0722B0099E85F /* _configset.c */; settings = {ATTRIBUTES = (); }; };
                159D54BB07529FFF004F8947 /* _configremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0205C0722B0099E85F /* _configremove.c */; settings = {ATTRIBUTES = (); }; };
-               159D54BC07529FFF004F8947 /* _configtouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0405C0722B0099E85F /* _configtouch.c */; settings = {ATTRIBUTES = (); }; };
                159D54BD07529FFF004F8947 /* _confignotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0605C0722B0099E85F /* _confignotify.c */; settings = {ATTRIBUTES = (); }; };
                159D54BE07529FFF004F8947 /* _notifyadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0805C0722B0099E85F /* _notifyadd.c */; settings = {ATTRIBUTES = (); }; };
                159D54BF07529FFF004F8947 /* _notifyremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0A05C0722B0099E85F /* _notifyremove.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2210D5B94190087BDA0 /* SCDPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695405C0722B0099E85F /* SCDPrivate.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2220D5B94190087BDA0 /* SCDPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695605C0722B0099E85F /* SCDPlugin.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2230D5B94190087BDA0 /* SCDOpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695805C0722B0099E85F /* SCDOpen.c */; settings = {ATTRIBUTES = (); }; };
-               15A5A2240D5B94190087BDA0 /* SCDLock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695A05C0722B0099E85F /* SCDLock.c */; settings = {ATTRIBUTES = (); }; };
-               15A5A2250D5B94190087BDA0 /* SCDUnlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695C05C0722B0099E85F /* SCDUnlock.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2260D5B94190087BDA0 /* SCDList.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695E05C0722B0099E85F /* SCDList.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2270D5B94190087BDA0 /* SCDAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696005C0722B0099E85F /* SCDAdd.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2280D5B94190087BDA0 /* SCDGet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696405C0722B0099E85F /* SCDGet.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2290D5B94190087BDA0 /* SCDSet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696605C0722B0099E85F /* SCDSet.c */; settings = {ATTRIBUTES = (); }; };
                15A5A22A0D5B94190087BDA0 /* SCDRemove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696805C0722B0099E85F /* SCDRemove.c */; settings = {ATTRIBUTES = (); }; };
-               15A5A22B0D5B94190087BDA0 /* SCDTouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696A05C0722B0099E85F /* SCDTouch.c */; settings = {ATTRIBUTES = (); }; };
                15A5A22C0D5B94190087BDA0 /* SCDNotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696C05C0722B0099E85F /* SCDNotify.c */; settings = {ATTRIBUTES = (); }; };
                15A5A22D0D5B94190087BDA0 /* SCDNotifierSetKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */; settings = {ATTRIBUTES = (); }; };
                15A5A22E0D5B94190087BDA0 /* SCDNotifierAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2300D5B94190087BDA0 /* SCDNotifierGetChanges.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2310D5B94190087BDA0 /* SCDNotifierWait.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697605C0722B0099E85F /* SCDNotifierWait.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2320D5B94190087BDA0 /* SCDNotifierInformViaCallback.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */; settings = {ATTRIBUTES = (); }; };
-               15A5A2330D5B94190087BDA0 /* SCDNotifierInformViaMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2340D5B94190087BDA0 /* SCDNotifierInformViaFD.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2350D5B94190087BDA0 /* SCDNotifierInformViaSignal.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */; settings = {ATTRIBUTES = (); }; };
                15A5A2360D5B94190087BDA0 /* SCDNotifierCancel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */; settings = {ATTRIBUTES = (); }; };
                15B274A5114467CD003414AD /* nc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B43727113C7BFC00EBF1B6 /* nc.c */; };
                15B274A6114467D8003414AD /* nc.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B43726113C7BFC00EBF1B6 /* nc.h */; };
                15BAA32307F0699A00D9EC95 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 15BAA32207F0699A00D9EC95 /* libbsm.dylib */; };
+               15C330BC134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */; };
+               15C330BD134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */; };
+               15C330BE134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */; };
+               15C330BF134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */; };
+               15C330C0134B92780028E36B /* rb.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B8134B92780028E36B /* rb.c */; };
+               15C330C1134B92780028E36B /* rb.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B8134B92780028E36B /* rb.c */; };
+               15C330C2134B92780028E36B /* rb.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B8134B92780028E36B /* rb.c */; };
+               15C330C3134B92780028E36B /* rb.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B8134B92780028E36B /* rb.c */; };
+               15C330C4134B92780028E36B /* rb.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330B9134B92780028E36B /* rb.h */; };
+               15C330C5134B92780028E36B /* rb.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330B9134B92780028E36B /* rb.h */; };
+               15C330C6134B92780028E36B /* rb.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330B9134B92780028E36B /* rb.h */; };
+               15C330C7134B92780028E36B /* rb.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330B9134B92780028E36B /* rb.h */; };
+               15C330D1134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */; };
+               15C330D2134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */; };
+               15C330D3134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */; };
+               15C330D4134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */; };
+               15C330E5134BD2AC0028E36B /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; };
+               15C330E6134BD2BB0028E36B /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; };
                15D48EBF0F67061600B4711E /* dnsinfo_create.c in Sources */ = {isa = PBXBuildFile; fileRef = 1521FC5C060F296A003B28F5 /* dnsinfo_create.c */; };
                15D48EC00F67061700B4711E /* dnsinfo_create.h in Headers */ = {isa = PBXBuildFile; fileRef = 1532629006281C9D00B1C10C /* dnsinfo_create.h */; };
                15D48EC10F67061F00B4711E /* dnsinfo_create.c in Sources */ = {isa = PBXBuildFile; fileRef = 1521FC5C060F296A003B28F5 /* dnsinfo_create.c */; };
                15D48EC20F67061F00B4711E /* dnsinfo_create.h in Headers */ = {isa = PBXBuildFile; fileRef = 1532629006281C9D00B1C10C /* dnsinfo_create.h */; };
                15D48ED30F67079B00B4711E /* shared_dns_info.defs in Sources */ = {isa = PBXBuildFile; fileRef = 15FCAAD005FD0EBF00CB79E6 /* shared_dns_info.defs */; };
                15D48ED40F6707A600B4711E /* shared_dns_info.defs in Sources */ = {isa = PBXBuildFile; fileRef = 15FCAAD005FD0EBF00CB79E6 /* shared_dns_info.defs */; };
+               15D8B22A1450D8450090CECF /* SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15D8B2291450D8450090CECF /* SCD.h */; };
+               15D8B22B1450D8450090CECF /* SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15D8B2291450D8450090CECF /* SCD.h */; };
+               15D8B22C1450D8450090CECF /* SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15D8B2291450D8450090CECF /* SCD.h */; };
+               15D8B22D1450D8450090CECF /* SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15D8B2291450D8450090CECF /* SCD.h */; };
                15D9DCFB10DD90A1004E545D /* AppWorkaround.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 15D9DCFA10DD90A1004E545D /* AppWorkaround.plist */; };
                15DAD5E1075913CE0084A6ED /* dnsinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 15B73F0905FD1B670096477F /* dnsinfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
                15DAD5E2075913CE0084A6ED /* dnsinfo_private.h in Headers */ = {isa = PBXBuildFile; fileRef = 15B73F0C05FD1B670096477F /* dnsinfo_private.h */; };
                15DAD66F07591A1A0084A6ED /* SCDPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695405C0722B0099E85F /* SCDPrivate.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67007591A1A0084A6ED /* SCDPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695605C0722B0099E85F /* SCDPlugin.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67107591A1A0084A6ED /* SCDOpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695805C0722B0099E85F /* SCDOpen.c */; settings = {ATTRIBUTES = (); }; };
-               15DAD67207591A1A0084A6ED /* SCDLock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695A05C0722B0099E85F /* SCDLock.c */; settings = {ATTRIBUTES = (); }; };
-               15DAD67307591A1A0084A6ED /* SCDUnlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695C05C0722B0099E85F /* SCDUnlock.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67407591A1A0084A6ED /* SCDList.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695E05C0722B0099E85F /* SCDList.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67507591A1A0084A6ED /* SCDAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696005C0722B0099E85F /* SCDAdd.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67607591A1A0084A6ED /* SCDGet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696405C0722B0099E85F /* SCDGet.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67707591A1A0084A6ED /* SCDSet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696605C0722B0099E85F /* SCDSet.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67807591A1A0084A6ED /* SCDRemove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696805C0722B0099E85F /* SCDRemove.c */; settings = {ATTRIBUTES = (); }; };
-               15DAD67907591A1A0084A6ED /* SCDTouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696A05C0722B0099E85F /* SCDTouch.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67A07591A1A0084A6ED /* SCDNotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696C05C0722B0099E85F /* SCDNotify.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67B07591A1A0084A6ED /* SCDNotifierSetKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67C07591A1A0084A6ED /* SCDNotifierAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67E07591A1A0084A6ED /* SCDNotifierGetChanges.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */; settings = {ATTRIBUTES = (); }; };
                15DAD67F07591A1A0084A6ED /* SCDNotifierWait.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697605C0722B0099E85F /* SCDNotifierWait.c */; settings = {ATTRIBUTES = (); }; };
                15DAD68007591A1A0084A6ED /* SCDNotifierInformViaCallback.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */; settings = {ATTRIBUTES = (); }; };
-               15DAD68107591A1A0084A6ED /* SCDNotifierInformViaMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */; settings = {ATTRIBUTES = (); }; };
                15DAD68207591A1A0084A6ED /* SCDNotifierInformViaFD.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */; settings = {ATTRIBUTES = (); }; };
                15DAD68307591A1A0084A6ED /* SCDNotifierInformViaSignal.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */; settings = {ATTRIBUTES = (); }; };
                15DAD68407591A1A0084A6ED /* SCDNotifierCancel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */; settings = {ATTRIBUTES = (); }; };
                15FEE80E0CCFD341001312F9 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15FEE80D0CCFD341001312F9 /* ApplicationServices.framework */; };
                15FEE81F0CD03E75001312F9 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 15FEE8180CD03CBB001312F9 /* Localizable.strings */; };
                15FF5C370CDF776200EEC8AA /* com.apple.SCHelper.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 15FF5C290CDF770500EEC8AA /* com.apple.SCHelper.plist */; };
+               7264C144147319E7004FD76D /* CaptiveNetwork.c in Sources */ = {isa = PBXBuildFile; fileRef = 15A1FF3110597F17004C9CC9 /* CaptiveNetwork.c */; };
+               7264C14614731A1F004FD76D /* CaptiveNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 15A1FF3010597F17004C9CC9 /* CaptiveNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; };
                72B43728113C7BFC00EBF1B6 /* nc.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B43726113C7BFC00EBF1B6 /* nc.h */; };
                72B43729113C7BFC00EBF1B6 /* nc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B43727113C7BFC00EBF1B6 /* nc.c */; };
                72B4372A113C7BFC00EBF1B6 /* nc.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B43726113C7BFC00EBF1B6 /* nc.h */; };
                72B4372B113C7BFC00EBF1B6 /* nc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B43727113C7BFC00EBF1B6 /* nc.c */; };
+               D661C2EF1368BB280030B977 /* network_information.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A781368913C0091C931 /* network_information.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               D661C2F11368BB600030B977 /* network_information.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A77136891300091C931 /* network_information.c */; };
+               D661C2F21368BB720030B977 /* network_information.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A781368913C0091C931 /* network_information.h */; settings = {ATTRIBUTES = (Public, ); }; };
                D6623873120B2AA7007F8E95 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1520A3DE0846B2DC0010B584 /* Security.framework */; };
+               D6986A79136891650091C931 /* network_information.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A77136891300091C931 /* network_information.c */; };
+               E49173E1137C4E4F0000089F /* network_information_priv.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A75136891120091C931 /* network_information_priv.c */; };
+               E4F211D3137B0AB900BBB915 /* network_information_priv.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A75136891120091C931 /* network_information_priv.c */; };
+               E4F211D4137B0ABD00BBB915 /* network_information_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A761368911E0091C931 /* network_information_priv.h */; };
+               E4F211D5137B0AD700BBB915 /* network_information_priv.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A75136891120091C931 /* network_information_priv.c */; };
+               E4F211D6137B0ADB00BBB915 /* network_information_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A761368911E0091C931 /* network_information_priv.h */; };
+               E4F211D7137B0AF200BBB915 /* network_information_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A761368911E0091C931 /* network_information_priv.h */; };
                F95B8A430B03E07A00993BA3 /* SCNetworkSignature.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */; };
                F95B8A460B03E09300993BA3 /* SCNetworkSignature.h in Headers */ = {isa = PBXBuildFile; fileRef = F95B8A440B03E09300993BA3 /* SCNetworkSignature.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F95B8A470B03E09300993BA3 /* SCNetworkSignaturePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = F95B8A450B03E09300993BA3 /* SCNetworkSignaturePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               F95B8A690B03F9B500993BA3 /* NetworkIdentification.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A680B03F97800993BA3 /* NetworkIdentification.c */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
                        remoteGlobalIDString = 151FE2DD0D5B7046000D6DB1;
                        remoteInfo = "configd_base-EmbeddedSimulator";
                };
-               1520A385084681350010B584 /* PBXContainerItemProxy */ = {
+               1521405A0E9400BF00DACD2C /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 1547001808455B98006787CE;
-                       remoteInfo = SCHelper;
+                       remoteGlobalIDString = 15213FF90E93E9F500DACD2C;
+                       remoteInfo = Logger.bundle;
                };
-               1521405A0E9400BF00DACD2C /* PBXContainerItemProxy */ = {
+               1528BFEB135731B800691881 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 15213FF90E93E9F500DACD2C;
-                       remoteInfo = Logger.bundle;
+                       remoteGlobalIDString = 1528BFDB1357305400691881;
+                       remoteInfo = SCNetworkReachability;
+               };
+               1528BFED135731B800691881 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 1528BFE31357309700691881;
+                       remoteInfo = SCNetworkReachability.bundle;
+               };
+               1528C00E135741C300691881 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 1528BFF013573FEE00691881;
+                       remoteInfo = "SCNetworkReachability-Embedded";
+               };
+               1528C010135741C300691881 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 1528BFF813573FF500691881;
+                       remoteInfo = "SCNetworkReachability.bundle-Embedded";
+               };
+               1528C0121357420300691881 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 1528BFFF1357401900691881;
+                       remoteInfo = "SCNetworkReachability-EmbeddedOther";
+               };
+               1528C0141357420300691881 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 1528C0071357401D00691881;
+                       remoteInfo = "SCNetworkReachability.bundle-EmbeddedOther";
                };
                1558480507550D470046C2E9 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        remoteGlobalIDString = 157A85260D56C91100B6F1A0;
                        remoteInfo = "LinkConfiguration-Embedded";
                };
-               157A854F0D56CA8800B6F1A0 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 157A85310D56C94F00B6F1A0;
-                       remoteInfo = "NetworkIdentification-Embedded";
-               };
                157A85510D56CA9E00B6F1A0 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
                        remoteGlobalIDString = 158317230CFB80A1006F62B9;
                        remoteInfo = "configd-Embedded";
                };
-               158317B20CFB8660006F62B9 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 158317A00CFB8626006F62B9;
-                       remoteInfo = "NetworkIdentification.bundle-Embedded";
-               };
                158317B40CFB8660006F62B9 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
                        remoteGlobalIDString = 1583EB32108395BD00A3BC0C;
                        remoteInfo = "PreferencesMonitor-EmbeddedOther";
                };
-               15AC5174108396D2004A9ED5 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 1583EB2B108395BD00A3BC0C;
-                       remoteInfo = "NetworkIdentification.bundle-EmbeddedOther";
-               };
-               15AC5176108396D2004A9ED5 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 1583EB23108395BD00A3BC0C;
-                       remoteInfo = "NetworkIdentification-EmbeddedOther";
-               };
                15AC5178108396D2004A9ED5 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
                        remoteGlobalIDString = 157A84D80D56C63900B6F1A0;
                        remoteInfo = "DNSConfiguration-Embedded";
                };
-               F95B8A760B03FB9100993BA3 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = F95B8A6A0B03F9D100993BA3;
-                       remoteInfo = NetworkIdentification.bundle;
-               };
-               F95B8A780B03FB9100993BA3 /* PBXContainerItemProxy */ = {
+               D6DDAC3C147A24BC00A2E902 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 15CB6A7705C0722B0099E85F /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = F95B8A5E0B03F81400993BA3;
-                       remoteInfo = NetworkIdentification;
+                       remoteGlobalIDString = 1547001808455B98006787CE;
+                       remoteInfo = SCHelper;
                };
 /* End PBXContainerItemProxy section */
 
                15213FFA0E93E9F500DACD2C /* Logger.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Logger.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                1521FC5C060F296A003B28F5 /* dnsinfo_create.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dnsinfo_create.c; path = dnsinfo/dnsinfo_create.c; sourceTree = SOURCE_ROOT; };
                1522FCE50FA7FD7000B24128 /* dnsinfo_flatfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsinfo_flatfile.c; path = dnsinfo/dnsinfo_flatfile.c; sourceTree = "<group>"; };
+               1528BFE21357305400691881 /* libSCNetworkReachability.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSCNetworkReachability.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               1528BFE81357309800691881 /* SCNetworkReachability.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCNetworkReachability.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+               1528BFE91357312E00691881 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Plugins/SCNetworkReachability/Info.plist; sourceTree = "<group>"; };
+               1528BFF713573FEE00691881 /* libSCNetworkReachability.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSCNetworkReachability.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               1528BFFE13573FF500691881 /* SCNetworkReachability.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCNetworkReachability.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+               1528C0061357401900691881 /* libSCNetworkReachability.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSCNetworkReachability.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               1528C00D1357401D00691881 /* SCNetworkReachability.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCNetworkReachability.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                152CEED0070CF6640050F23C /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = /usr/lib/libedit.2.dylib; sourceTree = "<absolute>"; };
                152E0E7E10FE820E00E402F2 /* helper.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = helper.defs; path = SystemConfiguration.fproj/helper/helper.defs; sourceTree = "<group>"; };
                152E0E8810FE824000E402F2 /* helper_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = helper_types.h; path = SystemConfiguration.fproj/helper/helper_types.h; sourceTree = "<group>"; };
                1559C4520D349A4E0098FD59 /* KernelEventMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KernelEventMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                1559C4530D349A4E0098FD59 /* LinkConfiguration.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinkConfiguration.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                1559C4540D349A4E0098FD59 /* PreferencesMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PreferencesMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
-               1559C4550D349A4E0098FD59 /* NetworkIdentification.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetworkIdentification.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                155A1E6B081079CC00F70D98 /* SCNetworkConfigurationPrivate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SCNetworkConfigurationPrivate.h; sourceTree = "<group>"; };
                155B7BF60847776D00F0E262 /* SCHelper_client.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SCHelper_client.h; path = helper/SCHelper_client.h; sourceTree = "<group>"; };
                155D22380AF13A7300D52ED0 /* dns-configuration.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "dns-configuration.h"; sourceTree = "<group>"; };
                157A850D0D56C8AA00B6F1A0 /* libInterfaceNamer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInterfaceNamer.a; sourceTree = BUILT_PRODUCTS_DIR; };
                157A85230D56C8E000B6F1A0 /* libKernelEventMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libKernelEventMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; };
                157A852E0D56C91100B6F1A0 /* libLinkConfiguration.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libLinkConfiguration.a; sourceTree = BUILT_PRODUCTS_DIR; };
-               157A85390D56C94F00B6F1A0 /* libNetworkIdentification.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNetworkIdentification.a; sourceTree = BUILT_PRODUCTS_DIR; };
                157A85440D56C96F00B6F1A0 /* libPreferencesMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPreferencesMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; };
                157A88880A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SCSchemaDefinitionsPrivate.h; sourceTree = "<group>"; };
                15828AE70753B5F900AD4710 /* KernelEventMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KernelEventMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
-               1583EA10108395BB00A3BC0C /* dnsinfo.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = dnsinfo.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+               1583EA10108395BB00A3BC0C /* libdnsinfo.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdnsinfo.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EA99108395BB00A3BC0C /* SystemConfiguration.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SystemConfiguration.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EAAA108395BB00A3BC0C /* SCHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SCHelper; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EAD8108395BB00A3BC0C /* libIPMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libIPMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EB0E108395BC00A3BC0C /* libLinkConfiguration.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libLinkConfiguration.a; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EB14108395BC00A3BC0C /* LinkConfiguration.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinkConfiguration.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EB21108395BC00A3BC0C /* Logger.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Logger.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
-               1583EB2A108395BD00A3BC0C /* libNetworkIdentification.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNetworkIdentification.a; sourceTree = BUILT_PRODUCTS_DIR; };
-               1583EB30108395BD00A3BC0C /* NetworkIdentification.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetworkIdentification.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EB39108395BD00A3BC0C /* libPreferencesMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPreferencesMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EB3F108395BD00A3BC0C /* PreferencesMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PreferencesMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                1583EB84108395BD00A3BC0C /* configd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = configd; sourceTree = BUILT_PRODUCTS_DIR; };
                15B73F0D05FD1B670096477F /* dnsinfo_server.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dnsinfo_server.c; path = dnsinfo/dnsinfo_server.c; sourceTree = "<group>"; };
                15B73F0E05FD1B670096477F /* dnsinfo_server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dnsinfo_server.h; path = dnsinfo/dnsinfo_server.h; sourceTree = "<group>"; };
                15BAA32207F0699A00D9EC95 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
+               15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SCNetworkReachabilityServer_client.c; path = reachability/SCNetworkReachabilityServer_client.c; sourceTree = "<group>"; };
+               15C330B8134B92780028E36B /* rb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rb.c; path = reachability/rb.c; sourceTree = "<group>"; };
+               15C330B9134B92780028E36B /* rb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rb.h; path = reachability/rb.h; sourceTree = "<group>"; };
+               15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SCNetworkReachabilityServer_server.c; path = reachability/SCNetworkReachabilityServer_server.c; sourceTree = "<group>"; };
+               15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCNetworkReachabilityInternal.h; sourceTree = "<group>"; };
                15CB691305C0722B0099E85F /* SystemConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SystemConfiguration.h; sourceTree = "<group>"; };
                15CB691505C0722B0099E85F /* SCPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCPrivate.h; sourceTree = "<group>"; };
                15CB691705C0722B0099E85F /* SCDPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCDPlugin.h; sourceTree = "<group>"; };
                15CB695405C0722B0099E85F /* SCDPrivate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDPrivate.c; sourceTree = "<group>"; };
                15CB695605C0722B0099E85F /* SCDPlugin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDPlugin.c; sourceTree = "<group>"; };
                15CB695805C0722B0099E85F /* SCDOpen.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDOpen.c; sourceTree = "<group>"; };
-               15CB695A05C0722B0099E85F /* SCDLock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDLock.c; sourceTree = "<group>"; };
-               15CB695C05C0722B0099E85F /* SCDUnlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDUnlock.c; sourceTree = "<group>"; };
                15CB695E05C0722B0099E85F /* SCDList.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDList.c; sourceTree = "<group>"; };
                15CB696005C0722B0099E85F /* SCDAdd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDAdd.c; sourceTree = "<group>"; };
                15CB696405C0722B0099E85F /* SCDGet.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDGet.c; sourceTree = "<group>"; };
                15CB696605C0722B0099E85F /* SCDSet.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDSet.c; sourceTree = "<group>"; };
                15CB696805C0722B0099E85F /* SCDRemove.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDRemove.c; sourceTree = "<group>"; };
-               15CB696A05C0722B0099E85F /* SCDTouch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDTouch.c; sourceTree = "<group>"; };
                15CB696C05C0722B0099E85F /* SCDNotify.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotify.c; sourceTree = "<group>"; };
                15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierSetKeys.c; sourceTree = "<group>"; };
                15CB697005C0722B0099E85F /* SCDNotifierAdd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierAdd.c; sourceTree = "<group>"; };
                15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierGetChanges.c; sourceTree = "<group>"; };
                15CB697605C0722B0099E85F /* SCDNotifierWait.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierWait.c; sourceTree = "<group>"; };
                15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierInformViaCallback.c; sourceTree = "<group>"; };
-               15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierInformViaMachPort.c; sourceTree = "<group>"; };
                15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierInformViaFD.c; sourceTree = "<group>"; };
                15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierInformViaSignal.c; sourceTree = "<group>"; };
                15CB698005C0722B0099E85F /* SCDNotifierCancel.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierCancel.c; sourceTree = "<group>"; };
                15CB69EC05C0722B0099E85F /* pattern.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pattern.c; sourceTree = "<group>"; };
                15CB69F005C0722B0099E85F /* _configopen.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configopen.c; sourceTree = "<group>"; };
                15CB69F205C0722B0099E85F /* _configclose.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configclose.c; sourceTree = "<group>"; };
-               15CB69F405C0722B0099E85F /* _configlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configlock.c; sourceTree = "<group>"; };
                15CB69F605C0722B0099E85F /* _configunlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configunlock.c; sourceTree = "<group>"; };
                15CB69F805C0722B0099E85F /* _configlist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configlist.c; sourceTree = "<group>"; };
                15CB69FA05C0722B0099E85F /* _configadd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configadd.c; sourceTree = "<group>"; };
                15CB69FE05C0722B0099E85F /* _configget.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configget.c; sourceTree = "<group>"; };
                15CB6A0005C0722B0099E85F /* _configset.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configset.c; sourceTree = "<group>"; };
                15CB6A0205C0722B0099E85F /* _configremove.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configremove.c; sourceTree = "<group>"; };
-               15CB6A0405C0722B0099E85F /* _configtouch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configtouch.c; sourceTree = "<group>"; };
                15CB6A0605C0722B0099E85F /* _confignotify.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _confignotify.c; sourceTree = "<group>"; };
                15CB6A0805C0722B0099E85F /* _notifyadd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _notifyadd.c; sourceTree = "<group>"; };
                15CB6A0A05C0722B0099E85F /* _notifyremove.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _notifyremove.c; sourceTree = "<group>"; };
                15CB6A6A05C0722B0099E85F /* scutil.8 */ = {isa = PBXFileReference; explicitFileType = text.man; path = scutil.8; sourceTree = "<group>"; };
                15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
                15CFC229068B222F00123568 /* get-mobility-info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.sh; path = "get-mobility-info"; sourceTree = SOURCE_ROOT; };
+               15D8B2291450D8450090CECF /* SCD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCD.h; sourceTree = "<group>"; };
                15D9DCFA10DD90A1004E545D /* AppWorkaround.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AppWorkaround.plist; sourceTree = "<group>"; };
                15DAD5EE075913CE0084A6ED /* libdnsinfo.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdnsinfo.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                15DAF2D808466D4900D1B2BD /* SCHelper_client.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = SCHelper_client.c; path = helper/SCHelper_client.c; sourceTree = "<group>"; };
                72B43726113C7BFC00EBF1B6 /* nc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nc.h; sourceTree = "<group>"; };
                72B43727113C7BFC00EBF1B6 /* nc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nc.c; sourceTree = "<group>"; };
                9EE943F306AF409B00772EB5 /* BondConfiguration.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = BondConfiguration.c; sourceTree = "<group>"; };
+               D6986A75136891120091C931 /* network_information_priv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = network_information_priv.c; path = nwi/network_information_priv.c; sourceTree = "<group>"; };
+               D6986A761368911E0091C931 /* network_information_priv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = network_information_priv.h; path = nwi/network_information_priv.h; sourceTree = "<group>"; };
+               D6986A77136891300091C931 /* network_information.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = network_information.c; path = nwi/network_information.c; sourceTree = "<group>"; };
+               D6986A781368913C0091C931 /* network_information.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = network_information.h; path = nwi/network_information.h; sourceTree = "<group>"; };
                F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = SCNetworkSignature.c; sourceTree = "<group>"; };
                F95B8A440B03E09300993BA3 /* SCNetworkSignature.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SCNetworkSignature.h; sourceTree = "<group>"; };
                F95B8A450B03E09300993BA3 /* SCNetworkSignaturePrivate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SCNetworkSignaturePrivate.h; sourceTree = "<group>"; };
-               F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNetworkIdentification.a; sourceTree = BUILT_PRODUCTS_DIR; };
-               F95B8A670B03F97800993BA3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               F95B8A680B03F97800993BA3 /* NetworkIdentification.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = NetworkIdentification.c; sourceTree = "<group>"; };
-               F95B8A700B03F9D100993BA3 /* NetworkIdentification.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetworkIdentification.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                                158317530CFB80A1006F62B9 /* libInterfaceNamer.a in Frameworks */,
                                158317540CFB80A1006F62B9 /* libIPMonitor.a in Frameworks */,
                                158317550CFB80A1006F62B9 /* libLinkConfiguration.a in Frameworks */,
-                               158317560CFB80A1006F62B9 /* libNetworkIdentification.a in Frameworks */,
                                158317570CFB80A1006F62B9 /* libPreferencesMonitor.a in Frameworks */,
+                               1528C0171357465900691881 /* libSCNetworkReachability.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                1583EB7A108395BD00A3BC0C /* libInterfaceNamer.a in Frameworks */,
                                1583EB7B108395BD00A3BC0C /* libIPMonitor.a in Frameworks */,
                                1583EB7C108395BD00A3BC0C /* libLinkConfiguration.a in Frameworks */,
-                               1583EB7D108395BD00A3BC0C /* libNetworkIdentification.a in Frameworks */,
                                1583EB7E108395BD00A3BC0C /* libPreferencesMonitor.a in Frameworks */,
+                               1528C01A135746D700691881 /* libSCNetworkReachability.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                159D54D007529FFF004F8947 /* libInterfaceNamer.a in Frameworks */,
                                159D54D107529FFF004F8947 /* libIPMonitor.a in Frameworks */,
                                159D54D207529FFF004F8947 /* libLinkConfiguration.a in Frameworks */,
-                               1533D77B0B10A14300CA4946 /* libNetworkIdentification.a in Frameworks */,
                                159D54D307529FFF004F8947 /* libPreferencesMonitor.a in Frameworks */,
+                               1528C019135746BB00691881 /* libSCNetworkReachability.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                1513E399108420A700088779 /* EmbeddedOther */ = {
                        isa = PBXGroup;
                        children = (
-                               1583EA10108395BB00A3BC0C /* dnsinfo.dylib */,
+                               1583EA10108395BB00A3BC0C /* libdnsinfo.dylib */,
                                1583EA99108395BB00A3BC0C /* SystemConfiguration.framework */,
                                1513E39D108420DE00088779 /* Plugins */,
                                1583EAAA108395BB00A3BC0C /* SCHelper */,
                                1583EB0E108395BC00A3BC0C /* libLinkConfiguration.a */,
                                1583EB14108395BC00A3BC0C /* LinkConfiguration.bundle */,
                                1583EB21108395BC00A3BC0C /* Logger.bundle */,
-                               1583EB2A108395BD00A3BC0C /* libNetworkIdentification.a */,
-                               1583EB30108395BD00A3BC0C /* NetworkIdentification.bundle */,
                                1583EB39108395BD00A3BC0C /* libPreferencesMonitor.a */,
                                1583EB3F108395BD00A3BC0C /* PreferencesMonitor.bundle */,
+                               1528C0061357401900691881 /* libSCNetworkReachability.a */,
+                               1528C00D1357401D00691881 /* SCNetworkReachability.bundle */,
                        );
                        name = Plugins;
                        sourceTree = "<group>";
                        name = SCMonitor;
                        sourceTree = "<group>";
                };
+               1528BFDA13572FC200691881 /* SCNetworkReachability */ = {
+                       isa = PBXGroup;
+                       children = (
+                               1528BFE91357312E00691881 /* Info.plist */,
+                       );
+                       name = SCNetworkReachability;
+                       sourceTree = "<group>";
+               };
                1531D3D90E93E6AA00248432 /* Logger */ = {
                        isa = PBXGroup;
                        children = (
                                156CA4850EF853BB00C59A18 /* Logger.bundle */,
                                157A85440D56C96F00B6F1A0 /* libPreferencesMonitor.a */,
                                1559C4540D349A4E0098FD59 /* PreferencesMonitor.bundle */,
-                               157A85390D56C94F00B6F1A0 /* libNetworkIdentification.a */,
-                               1559C4550D349A4E0098FD59 /* NetworkIdentification.bundle */,
+                               1528BFF713573FEE00691881 /* libSCNetworkReachability.a */,
+                               1528BFFE13573FF500691881 /* SCNetworkReachability.bundle */,
                        );
                        name = Plugins;
                        sourceTree = "<group>";
                                15FF5C390CDF9C4000EEC8AA /* Supporting Files */,
                        );
                        name = SCHelper;
-                       path = SystemConfiguration.fproj;
                        sourceTree = "<group>";
                };
                1547002F084561ED006787CE /* Headers */ = {
                                15828AE70753B5F900AD4710 /* KernelEventMonitor.bundle */,
                                159D53F307528C79004F8947 /* libLinkConfiguration.a */,
                                15FD72B50754DA69001CC321 /* LinkConfiguration.bundle */,
-                               F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */,
                                15213FFA0E93E9F500DACD2C /* Logger.bundle */,
-                               F95B8A700B03F9D100993BA3 /* NetworkIdentification.bundle */,
                                159D53FA07528C95004F8947 /* libPreferencesMonitor.a */,
                                15FD72C90754DA7E001CC321 /* PreferencesMonitor.bundle */,
+                               1528BFE21357305400691881 /* libSCNetworkReachability.a */,
+                               1528BFE81357309800691881 /* SCNetworkReachability.bundle */,
                        );
                        name = Plugins;
                        sourceTree = "<group>";
                                159D53AF07528B36004F8947 /* KernelEventMonitor */,
                                159D53C007528B36004F8947 /* LinkConfiguration */,
                                1531D3D90E93E6AA00248432 /* Logger */,
-                               F95B8A660B03F97800993BA3 /* NetworkIdentification */,
                                159D53C207528B36004F8947 /* PreferencesMonitor */,
+                               1528BFDA13572FC200691881 /* SCNetworkReachability */,
                        );
                        name = Plugins;
                        sourceTree = "<group>";
                        name = "Supporting Files";
                        sourceTree = "<group>";
                };
-               15CB68FC05C072220099E85F /* configd */ = {
+               15C330B4134B91930028E36B /* SCNetworkReachability */ = {
                        isa = PBXGroup;
                        children = (
-                               15CB6A8605C072500099E85F /* MiG */,
-                               15CB6A8305C072410099E85F /* Schema */,
-                               1582B36B05FD1A4D009C2750 /* DNSConfiguration */,
-                               15CB690705C0722A0099E85F /* SystemConfiguration */,
-                               1547002E084561B4006787CE /* SCHelper */,
-                               151F5DA80CCE995D0093AC3B /* SCMonitor */,
-                               15CB69C205C0722B0099E85F /* configd */,
-                               15CB6A2205C0722B0099E85F /* scselect */,
-                               15CB6A3705C0722B0099E85F /* scutil */,
-                               159D53A207528B06004F8947 /* Plugins */,
-                               15CB6A6E05C0722B0099E85F /* External Frameworks and Libraries */,
-                               15CB690F05C0722B0099E85F /* Products */,
-                               15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */,
-                               15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */,
+                               15C330B5134B91C40028E36B /* Headers */,
+                               15C330B6134B91CB0028E36B /* Sources */,
                        );
-                       indentWidth = 8;
-                       name = configd;
+                       name = SCNetworkReachability;
                        sourceTree = "<group>";
-                       tabWidth = 8;
-                       usesTabs = 1;
                };
-               15CB690705C0722A0099E85F /* SystemConfiguration */ = {
+               15C330B5134B91C40028E36B /* Headers */ = {
                        isa = PBXGroup;
                        children = (
-                               15CB691205C0722B0099E85F /* Headers */,
-                               15CB694F05C0722B0099E85F /* Sources */,
-                               15B6861D0678B61900FF4023 /* Supporting Files */,
+                               15CB693705C0722B0099E85F /* SCNetworkReachability.h */,
+                               15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */,
+                               15C330B9134B92780028E36B /* rb.h */,
                        );
-                       name = SystemConfiguration;
-                       path = SystemConfiguration.fproj;
+                       name = Headers;
                        sourceTree = "<group>";
                };
-               15CB690F05C0722B0099E85F /* Products */ = {
+               15C330B6134B91CB0028E36B /* Sources */ = {
                        isa = PBXGroup;
                        children = (
-                               151F63EC09328A3C0096DCC9 /* genSCPreferences */,
-                               154083530D5B824400E07907 /* MacOSX */,
-                               1540835A0D5B825200E07907 /* Embedded */,
-                               154083890D5B82A900E07907 /* EmbeddedSimulator */,
-                               1513E399108420A700088779 /* EmbeddedOther */,
+                               15CB69A205C0722B0099E85F /* SCNetwork.c */,
+                               15CB69A605C0722B0099E85F /* SCNetworkReachability.c */,
+                               15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */,
+                               15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */,
+                               15C330B8134B92780028E36B /* rb.c */,
                        );
-                       name = Products;
+                       name = Sources;
                        sourceTree = "<group>";
                };
-               15CB691205C0722B0099E85F /* Headers */ = {
+               15C330D5134B99EF0028E36B /* SCDynamicStore */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15C330D6134B9A1C0028E36B /* Headers */,
+                               15C330D7134B9A290028E36B /* Sources */,
+                       );
+                       name = SCDynamicStore;
+                       sourceTree = "<group>";
+               };
+               15C330D6134B9A1C0028E36B /* Headers */ = {
                        isa = PBXGroup;
                        children = (
-                               15CB691305C0722B0099E85F /* SystemConfiguration.h */,
-                               150607DE075A00A300B147BA /* SCSchemaDefinitions.h */,
-                               157A88880A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h */,
-                               15CB691705C0722B0099E85F /* SCDPlugin.h */,
                                15CB691B05C0722B0099E85F /* SCDynamicStoreInternal.h */,
                                15CB691D05C0722B0099E85F /* SCDynamicStore.h */,
                                15CB691F05C0722B0099E85F /* SCDynamicStorePrivate.h */,
                                15CB692305C0722B0099E85F /* SCDynamicStoreCopySpecific.h */,
                                15CB692505C0722B0099E85F /* SCDynamicStoreCopySpecificPrivate.h */,
                                15CB692705C0722B0099E85F /* SCDynamicStoreSetSpecificPrivate.h */,
-                               15CB692905C0722B0099E85F /* SCPreferencesInternal.h */,
-                               15CB692B05C0722B0099E85F /* SCPreferences.h */,
-                               15CB692D05C0722B0099E85F /* SCPreferencesPrivate.h */,
-                               15CB692F05C0722B0099E85F /* SCPreferencesPath.h */,
-                               151BDA2B05D9E28B00657BC7 /* SCPreferencesPathKey.h */,
-                               154CF3F307E1EA4D00D8302E /* SCPreferencesGetSpecificPrivate.h */,
-                               15CB693105C0722B0099E85F /* SCPreferencesSetSpecific.h */,
-                               156BD6BB07E0DFA9008698FF /* SCPreferencesSetSpecificPrivate.h */,
-                               152E68C00A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h */,
-                               15CB691505C0722B0099E85F /* SCPrivate.h */,
-                               15AD7A380670A85900BFE03C /* SCNetworkConfiguration.h */,
-                               155A1E6B081079CC00F70D98 /* SCNetworkConfigurationPrivate.h */,
-                               15AD7A3A0670A85900BFE03C /* SCNetworkConfigurationInternal.h */,
-                               15CB693305C0722B0099E85F /* SCNetwork.h */,
-                               15CB693505C0722B0099E85F /* SCNetworkConnection.h */,
-                               15A2972E0A13C08C009879B3 /* SCNetworkConnectionPrivate.h */,
-                               15CB693705C0722B0099E85F /* SCNetworkReachability.h */,
-                               F95B8A440B03E09300993BA3 /* SCNetworkSignature.h */,
-                               F95B8A450B03E09300993BA3 /* SCNetworkSignaturePrivate.h */,
-                               15CB693905C0722B0099E85F /* SCValidation.h */,
-                               15A1FF3010597F17004C9CC9 /* CaptiveNetwork.h */,
-                               15CB694505C0722B0099E85F /* DeviceOnHold.h */,
-                               15CB693D05C0722B0099E85F /* DHCPClientPreferences.h */,
-                               15CB694705C0722B0099E85F /* LinkConfiguration.h */,
-                               15CB694905C0722B0099E85F /* dy_framework.h */,
-                               15CB694305C0722B0099E85F /* moh.h */,
-                               15CB694105C0722B0099E85F /* moh_msg.h */,
-                               23C1E2BE062DD5DB00835B54 /* pppcontroller.h */,
-                               159A7513107FEAA400A57EAB /* VPNPrivate.h */,
-                               159A7515107FEAA400A57EAB /* VPNConfiguration.h */,
-                               15AAA7F2108E310700C2A607 /* VPNTunnel.h */,
-                               15AAA7F1108E310700C2A607 /* VPNTunnelPrivate.h */,
                        );
                        name = Headers;
                        sourceTree = "<group>";
                };
-               15CB694F05C0722B0099E85F /* Sources */ = {
+               15C330D7134B9A290028E36B /* Sources */ = {
                        isa = PBXGroup;
                        children = (
-                               150607BD075A00A200B147BA /* SCSchemaDefinitions.c */,
-                               15CB695005C0722B0099E85F /* SCD.c */,
-                               15CB695405C0722B0099E85F /* SCDPrivate.c */,
                                15CB695205C0722B0099E85F /* SCDKeys.c */,
                                15CB695805C0722B0099E85F /* SCDOpen.c */,
-                               15CB695A05C0722B0099E85F /* SCDLock.c */,
-                               15CB695C05C0722B0099E85F /* SCDUnlock.c */,
                                15CB695E05C0722B0099E85F /* SCDList.c */,
                                15CB696005C0722B0099E85F /* SCDAdd.c */,
                                15CB696405C0722B0099E85F /* SCDGet.c */,
                                15CB696605C0722B0099E85F /* SCDSet.c */,
                                15CB696805C0722B0099E85F /* SCDRemove.c */,
-                               15CB696A05C0722B0099E85F /* SCDTouch.c */,
                                15CB696C05C0722B0099E85F /* SCDNotify.c */,
                                15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */,
                                15CB697005C0722B0099E85F /* SCDNotifierAdd.c */,
                                15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */,
                                15CB697605C0722B0099E85F /* SCDNotifierWait.c */,
                                15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */,
-                               15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */,
                                15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */,
                                15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */,
                                15CB698005C0722B0099E85F /* SCDNotifierCancel.c */,
                                15CB698205C0722B0099E85F /* SCDSnapshot.c */,
+                       );
+                       name = Sources;
+                       sourceTree = "<group>";
+               };
+               15C330D8134B9A730028E36B /* SCPreferences */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15C330D9134B9A850028E36B /* Headers */,
+                               15C330DA134B9A940028E36B /* Sources */,
+                       );
+                       name = SCPreferences;
+                       sourceTree = "<group>";
+               };
+               15C330D9134B9A850028E36B /* Headers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15CB692905C0722B0099E85F /* SCPreferencesInternal.h */,
+                               15CB692B05C0722B0099E85F /* SCPreferences.h */,
+                               15CB692D05C0722B0099E85F /* SCPreferencesPrivate.h */,
+                               15CB692F05C0722B0099E85F /* SCPreferencesPath.h */,
+                               151BDA2B05D9E28B00657BC7 /* SCPreferencesPathKey.h */,
+                               154CF3F307E1EA4D00D8302E /* SCPreferencesGetSpecificPrivate.h */,
+                               15CB693105C0722B0099E85F /* SCPreferencesSetSpecific.h */,
+                               156BD6BB07E0DFA9008698FF /* SCPreferencesSetSpecificPrivate.h */,
+                               152E68C00A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h */,
+                       );
+                       name = Headers;
+                       sourceTree = "<group>";
+               };
+               15C330DA134B9A940028E36B /* Sources */ = {
+                       isa = PBXGroup;
+                       children = (
                                15CB698405C0722B0099E85F /* SCP.c */,
                                15CB698605C0722B0099E85F /* SCPOpen.c */,
                                15CB698805C0722B0099E85F /* SCPLock.c */,
                                15CB699A05C0722B0099E85F /* SCPPath.c */,
                                151BDA5D05D9E2ED00657BC7 /* SCPreferencesPathKey.c */,
                                152E68C20A2C89E30011FDA8 /* SCPreferencesKeychainPrivate.c */,
+                       );
+                       name = Sources;
+                       sourceTree = "<group>";
+               };
+               15C330DB134B9B8B0028E36B /* SCNetworkConfiguration */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15C330DC134B9BA20028E36B /* Headers */,
+                               15C330DD134B9BB20028E36B /* Sources */,
+                       );
+                       name = SCNetworkConfiguration;
+                       sourceTree = "<group>";
+               };
+               15C330DC134B9BA20028E36B /* Headers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15AD7A380670A85900BFE03C /* SCNetworkConfiguration.h */,
+                               155A1E6B081079CC00F70D98 /* SCNetworkConfigurationPrivate.h */,
+                               15AD7A3A0670A85900BFE03C /* SCNetworkConfigurationInternal.h */,
+                               15CB694705C0722B0099E85F /* LinkConfiguration.h */,
+                       );
+                       name = Headers;
+                       sourceTree = "<group>";
+               };
+               15C330DD134B9BB20028E36B /* Sources */ = {
+                       isa = PBXGroup;
+                       children = (
                                15AD7A390670A85900BFE03C /* SCNetworkConfigurationInternal.c */,
                                15AD7A3B0670A85900BFE03C /* SCNetworkInterface.c */,
                                15AD7A3C0670A85900BFE03C /* SCNetworkProtocol.c */,
                                9EE943F306AF409B00772EB5 /* BondConfiguration.c */,
                                15FD7B3B101E439200C56621 /* BridgeConfiguration.c */,
                                15CB69B605C0722B0099E85F /* VLANConfiguration.c */,
-                               15CB695605C0722B0099E85F /* SCDPlugin.c */,
-                               15CB699C05C0722B0099E85F /* SCDConsoleUser.c */,
-                               15CB699E05C0722B0099E85F /* SCDHostName.c */,
-                               15CB69A005C0722B0099E85F /* SCLocation.c */,
-                               15CB69A205C0722B0099E85F /* SCNetwork.c */,
+                       );
+                       name = Sources;
+                       sourceTree = "<group>";
+               };
+               15C330DE134B9C290028E36B /* SCNetworkConnection */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15C330E0134B9C4C0028E36B /* Headers */,
+                               15C330DF134B9C3F0028E36B /* Sources */,
+                       );
+                       name = SCNetworkConnection;
+                       sourceTree = "<group>";
+               };
+               15C330DF134B9C3F0028E36B /* Sources */ = {
+                       isa = PBXGroup;
+                       children = (
                                15CB69A405C0722B0099E85F /* SCNetworkConnection.c */,
                                15A2972D0A13C08C009879B3 /* SCNetworkConnectionPrivate.c */,
-                               15CB69A605C0722B0099E85F /* SCNetworkReachability.c */,
-                               F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */,
-                               15CB69A805C0722B0099E85F /* SCProxies.c */,
-                               15A1FF3110597F17004C9CC9 /* CaptiveNetwork.c */,
-                               15CB69AC05C0722B0099E85F /* DHCP.c */,
-                               15CB69AE05C0722B0099E85F /* moh.c */,
-                               15CB69B005C0722B0099E85F /* DeviceOnHold.c */,
-                               15CB69B405C0722B0099E85F /* dy_framework.c */,
-                               159A7517107FEAA400A57EAB /* VPNPrivate.c */,
-                               159A7519107FEAA400A57EAB /* VPNConfiguration.c */,
-                               15AAA7F3108E310700C2A607 /* VPNTunnel.c */,
                        );
                        name = Sources;
                        sourceTree = "<group>";
                };
-               15CB69C205C0722B0099E85F /* configd */ = {
+               15C330E0134B9C4C0028E36B /* Headers */ = {
                        isa = PBXGroup;
                        children = (
-                               15CB69CE05C0722B0099E85F /* Headers */,
-                               15CB69DF05C0722B0099E85F /* Sources */,
-                               15CB6A1805C0722B0099E85F /* Supporting Files */,
+                               15CB693505C0722B0099E85F /* SCNetworkConnection.h */,
+                               15A2972E0A13C08C009879B3 /* SCNetworkConnectionPrivate.h */,
+                               23C1E2BE062DD5DB00835B54 /* pppcontroller.h */,
                        );
-                       name = configd;
-                       path = configd.tproj;
+                       name = Headers;
                        sourceTree = "<group>";
                };
-               15CB69CE05C0722B0099E85F /* Headers */ = {
+               15C330E1134B9C8E0028E36B /* VPN */ = {
                        isa = PBXGroup;
                        children = (
-                               15CB69CF05C0722B0099E85F /* configd.h */,
-                               15CB69D105C0722B0099E85F /* _SCD.h */,
-                               15CB69D305C0722B0099E85F /* configd_server.h */,
-                               15CB69D505C0722B0099E85F /* notify_server.h */,
-                               15CB69D705C0722B0099E85F /* plugin_support.h */,
-                               15CB69D905C0722B0099E85F /* session.h */,
-                               15CB69DB05C0722B0099E85F /* pattern.h */,
+                               15C330E3134B9CA30028E36B /* Headers */,
+                               15C330E2134B9C9B0028E36B /* Sources */,
                        );
-                       name = Headers;
+                       name = VPN;
                        sourceTree = "<group>";
                };
-               15CB69DF05C0722B0099E85F /* Sources */ = {
+               15C330E2134B9C9B0028E36B /* Sources */ = {
                        isa = PBXGroup;
                        children = (
-                               15CB69E005C0722B0099E85F /* configd.m */,
-                               15CB69E205C0722B0099E85F /* _SCD.c */,
-                               15CB69E405C0722B0099E85F /* configd_server.c */,
-                               15CB69E605C0722B0099E85F /* notify_server.c */,
-                               15CB69E805C0722B0099E85F /* plugin_support.c */,
-                               15CB69EA05C0722B0099E85F /* session.c */,
-                               15CB69EC05C0722B0099E85F /* pattern.c */,
-                               15CB69F005C0722B0099E85F /* _configopen.c */,
-                               15CB69F205C0722B0099E85F /* _configclose.c */,
-                               15CB69F405C0722B0099E85F /* _configlock.c */,
-                               15CB69F605C0722B0099E85F /* _configunlock.c */,
-                               15CB69F805C0722B0099E85F /* _configlist.c */,
+                               159A7517107FEAA400A57EAB /* VPNPrivate.c */,
+                               159A7519107FEAA400A57EAB /* VPNConfiguration.c */,
+                               15AAA7F3108E310700C2A607 /* VPNTunnel.c */,
+                       );
+                       name = Sources;
+                       sourceTree = "<group>";
+               };
+               15C330E3134B9CA30028E36B /* Headers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               159A7513107FEAA400A57EAB /* VPNPrivate.h */,
+                               159A7515107FEAA400A57EAB /* VPNConfiguration.h */,
+                               15AAA7F2108E310700C2A607 /* VPNTunnel.h */,
+                               15AAA7F1108E310700C2A607 /* VPNTunnelPrivate.h */,
+                       );
+                       name = Headers;
+                       sourceTree = "<group>";
+               };
+               15CB68FC05C072220099E85F /* configd */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15CB6A8605C072500099E85F /* MiG */,
+                               15CB6A8305C072410099E85F /* Schema */,
+                               D6986A70136890B60091C931 /* NetworkInformation */,
+                               1582B36B05FD1A4D009C2750 /* DNSConfiguration */,
+                               15CB690705C0722A0099E85F /* SystemConfiguration */,
+                               151F5DA80CCE995D0093AC3B /* SCMonitor */,
+                               15CB69C205C0722B0099E85F /* configd */,
+                               15CB6A2205C0722B0099E85F /* scselect */,
+                               15CB6A3705C0722B0099E85F /* scutil */,
+                               159D53A207528B06004F8947 /* Plugins */,
+                               15CB6A6E05C0722B0099E85F /* External Frameworks and Libraries */,
+                               15CB690F05C0722B0099E85F /* Products */,
+                               15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */,
+                               15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */,
+                       );
+                       indentWidth = 8;
+                       name = configd;
+                       sourceTree = "<group>";
+                       tabWidth = 8;
+                       usesTabs = 1;
+               };
+               15CB690705C0722A0099E85F /* SystemConfiguration */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15C330D5134B99EF0028E36B /* SCDynamicStore */,
+                               15C330D8134B9A730028E36B /* SCPreferences */,
+                               1547002E084561B4006787CE /* SCHelper */,
+                               15C330DB134B9B8B0028E36B /* SCNetworkConfiguration */,
+                               15C330DE134B9C290028E36B /* SCNetworkConnection */,
+                               15C330B4134B91930028E36B /* SCNetworkReachability */,
+                               15C330E1134B9C8E0028E36B /* VPN */,
+                               15CB691205C0722B0099E85F /* Other Headers */,
+                               15CB694F05C0722B0099E85F /* Other Sources */,
+                               15B6861D0678B61900FF4023 /* Supporting Files */,
+                       );
+                       name = SystemConfiguration;
+                       path = SystemConfiguration.fproj;
+                       sourceTree = "<group>";
+               };
+               15CB690F05C0722B0099E85F /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               151F63EC09328A3C0096DCC9 /* genSCPreferences */,
+                               154083530D5B824400E07907 /* MacOSX */,
+                               1540835A0D5B825200E07907 /* Embedded */,
+                               154083890D5B82A900E07907 /* EmbeddedSimulator */,
+                               1513E399108420A700088779 /* EmbeddedOther */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               15CB691205C0722B0099E85F /* Other Headers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15D8B2291450D8450090CECF /* SCD.h */,
+                               15CB691305C0722B0099E85F /* SystemConfiguration.h */,
+                               150607DE075A00A300B147BA /* SCSchemaDefinitions.h */,
+                               157A88880A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h */,
+                               15CB691705C0722B0099E85F /* SCDPlugin.h */,
+                               15CB691505C0722B0099E85F /* SCPrivate.h */,
+                               15CB693305C0722B0099E85F /* SCNetwork.h */,
+                               F95B8A440B03E09300993BA3 /* SCNetworkSignature.h */,
+                               F95B8A450B03E09300993BA3 /* SCNetworkSignaturePrivate.h */,
+                               15CB693905C0722B0099E85F /* SCValidation.h */,
+                               15A1FF3010597F17004C9CC9 /* CaptiveNetwork.h */,
+                               15CB694505C0722B0099E85F /* DeviceOnHold.h */,
+                               15CB693D05C0722B0099E85F /* DHCPClientPreferences.h */,
+                               15CB694905C0722B0099E85F /* dy_framework.h */,
+                               15CB694305C0722B0099E85F /* moh.h */,
+                               15CB694105C0722B0099E85F /* moh_msg.h */,
+                       );
+                       name = "Other Headers";
+                       sourceTree = "<group>";
+               };
+               15CB694F05C0722B0099E85F /* Other Sources */ = {
+                       isa = PBXGroup;
+                       children = (
+                               150607BD075A00A200B147BA /* SCSchemaDefinitions.c */,
+                               15CB695005C0722B0099E85F /* SCD.c */,
+                               15CB695405C0722B0099E85F /* SCDPrivate.c */,
+                               15CB695605C0722B0099E85F /* SCDPlugin.c */,
+                               15CB699C05C0722B0099E85F /* SCDConsoleUser.c */,
+                               15CB699E05C0722B0099E85F /* SCDHostName.c */,
+                               15CB69A005C0722B0099E85F /* SCLocation.c */,
+                               F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */,
+                               15CB69A805C0722B0099E85F /* SCProxies.c */,
+                               15A1FF3110597F17004C9CC9 /* CaptiveNetwork.c */,
+                               15CB69AC05C0722B0099E85F /* DHCP.c */,
+                               15CB69AE05C0722B0099E85F /* moh.c */,
+                               15CB69B005C0722B0099E85F /* DeviceOnHold.c */,
+                               15CB69B405C0722B0099E85F /* dy_framework.c */,
+                       );
+                       name = "Other Sources";
+                       sourceTree = "<group>";
+               };
+               15CB69C205C0722B0099E85F /* configd */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15CB69CE05C0722B0099E85F /* Headers */,
+                               15CB69DF05C0722B0099E85F /* Sources */,
+                               15CB6A1805C0722B0099E85F /* Supporting Files */,
+                       );
+                       name = configd;
+                       path = configd.tproj;
+                       sourceTree = "<group>";
+               };
+               15CB69CE05C0722B0099E85F /* Headers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15CB69CF05C0722B0099E85F /* configd.h */,
+                               15CB69D105C0722B0099E85F /* _SCD.h */,
+                               15CB69D305C0722B0099E85F /* configd_server.h */,
+                               15CB69D505C0722B0099E85F /* notify_server.h */,
+                               15CB69D705C0722B0099E85F /* plugin_support.h */,
+                               15CB69D905C0722B0099E85F /* session.h */,
+                               15CB69DB05C0722B0099E85F /* pattern.h */,
+                       );
+                       name = Headers;
+                       sourceTree = "<group>";
+               };
+               15CB69DF05C0722B0099E85F /* Sources */ = {
+                       isa = PBXGroup;
+                       children = (
+                               15CB69E005C0722B0099E85F /* configd.m */,
+                               15CB69E205C0722B0099E85F /* _SCD.c */,
+                               15CB69E405C0722B0099E85F /* configd_server.c */,
+                               15CB69E605C0722B0099E85F /* notify_server.c */,
+                               15CB69E805C0722B0099E85F /* plugin_support.c */,
+                               15CB69EA05C0722B0099E85F /* session.c */,
+                               15CB69EC05C0722B0099E85F /* pattern.c */,
+                               15CB69F005C0722B0099E85F /* _configopen.c */,
+                               15CB69F205C0722B0099E85F /* _configclose.c */,
+                               15CB69F605C0722B0099E85F /* _configunlock.c */,
+                               15CB69F805C0722B0099E85F /* _configlist.c */,
                                15CB69FA05C0722B0099E85F /* _configadd.c */,
                                15CB69FE05C0722B0099E85F /* _configget.c */,
                                15CB6A0005C0722B0099E85F /* _configset.c */,
                                15CB6A0205C0722B0099E85F /* _configremove.c */,
-                               15CB6A0405C0722B0099E85F /* _configtouch.c */,
                                15CB6A0605C0722B0099E85F /* _confignotify.c */,
                                15CB6A0805C0722B0099E85F /* _notifyadd.c */,
                                15CB6A0A05C0722B0099E85F /* _notifyremove.c */,
                        name = "Supporting Files";
                        sourceTree = "<group>";
                };
-               F95B8A660B03F97800993BA3 /* NetworkIdentification */ = {
+               D6986A70136890B60091C931 /* NetworkInformation */ = {
+                       isa = PBXGroup;
+                       children = (
+                               D6986A72136890C90091C931 /* Headers */,
+                               D6986A74136890DB0091C931 /* Sources */,
+                       );
+                       name = NetworkInformation;
+                       sourceTree = "<group>";
+               };
+               D6986A72136890C90091C931 /* Headers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               D6986A781368913C0091C931 /* network_information.h */,
+                               D6986A761368911E0091C931 /* network_information_priv.h */,
+                       );
+                       name = Headers;
+                       sourceTree = "<group>";
+               };
+               D6986A74136890DB0091C931 /* Sources */ = {
                        isa = PBXGroup;
                        children = (
-                               F95B8A670B03F97800993BA3 /* Info.plist */,
-                               F95B8A680B03F97800993BA3 /* NetworkIdentification.c */,
+                               D6986A77136891300091C931 /* network_information.c */,
+                               D6986A75136891120091C931 /* network_information_priv.c */,
                        );
-                       name = NetworkIdentification;
-                       path = Plugins/NetworkIdentification;
+                       name = Sources;
                        sourceTree = "<group>";
                };
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
+               1528BFDC1357305400691881 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               1528BFF113573FEE00691881 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               1528C0001357401900691881 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                1547001908455B98006787CE /* Headers */ = {
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                                159A751C107FEAA400A57EAB /* VPNConfiguration.h in Headers */,
                                15AAA7F5108E310700C2A607 /* VPNTunnel.h in Headers */,
                                15AAA7F4108E310700C2A607 /* VPNTunnelPrivate.h in Headers */,
+                               15C330C5134B92780028E36B /* rb.h in Headers */,
+                               15C330D2134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */,
+                               15D8B22B1450D8450090CECF /* SCD.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                157A84DA0D56C63900B6F1A0 /* dnsinfo.h in Headers */,
+                               D661C2F21368BB720030B977 /* network_information.h in Headers */,
                                157A84DB0D56C63900B6F1A0 /* dnsinfo_private.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        buildActionMask = 2147483647;
                        files = (
                                157A84F60D56C7E800B6F1A0 /* dns-configuration.h in Headers */,
+                               15D48EC20F67061F00B4711E /* dnsinfo_create.h in Headers */,
+                               E4F211D4137B0ABD00BBB915 /* network_information_priv.h in Headers */,
                                1575FD2812CD15C60003D86E /* proxy-configuration.h in Headers */,
                                157A84F70D56C7E800B6F1A0 /* set-hostname.h in Headers */,
-                               15D48EC20F67061F00B4711E /* dnsinfo_create.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               157A85320D56C94F00B6F1A0 /* Headers */ = {
-                       isa = PBXHeadersBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                157A853D0D56C96F00B6F1A0 /* Headers */ = {
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        buildActionMask = 2147483647;
                        files = (
                                1583EA06108395BB00A3BC0C /* dnsinfo.h in Headers */,
+                               151E0CA31378EE1000C5DA2A /* network_information.h in Headers */,
                                1583EA07108395BB00A3BC0C /* dnsinfo_private.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                                1583EA42108395BB00A3BC0C /* SCNetworkSignature.h in Headers */,
                                1583EA43108395BB00A3BC0C /* SCNetworkSignaturePrivate.h in Headers */,
                                1583EA44108395BB00A3BC0C /* CaptiveNetwork.h in Headers */,
+                               15C330C7134B92780028E36B /* rb.h in Headers */,
+                               15C330D4134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */,
+                               15D8B22D1450D8450090CECF /* SCD.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                1583EACC108395BB00A3BC0C /* dns-configuration.h in Headers */,
+                               1583EACE108395BB00A3BC0C /* dnsinfo_create.h in Headers */,
+                               E4F211D6137B0ADB00BBB915 /* network_information_priv.h in Headers */,
                                1575FD2C12CD15C60003D86E /* proxy-configuration.h in Headers */,
                                1583EACD108395BB00A3BC0C /* set-hostname.h in Headers */,
-                               1583EACE108395BB00A3BC0C /* dnsinfo_create.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               1583EB24108395BD00A3BC0C /* Headers */ = {
-                       isa = PBXHeadersBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                1583EB33108395BD00A3BC0C /* Headers */ = {
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        buildActionMask = 2147483647;
                        files = (
                                155D223B0AF13A7300D52ED0 /* dns-configuration.h in Headers */,
+                               15D48EC00F67061700B4711E /* dnsinfo_create.h in Headers */,
+                               E4F211D7137B0AF200BBB915 /* network_information_priv.h in Headers */,
                                1575FD2A12CD15C60003D86E /* proxy-configuration.h in Headers */,
                                155D223C0AF13A7300D52ED0 /* set-hostname.h in Headers */,
                                155D223D0AF13A7300D52ED0 /* smb-configuration.h in Headers */,
-                               15D48EC00F67061700B4711E /* dnsinfo_create.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                15A1FF3410597F17004C9CC9 /* CaptiveNetwork.h in Headers */,
                                159A7528107FEAA400A57EAB /* VPNPrivate.h in Headers */,
                                159A752A107FEAA400A57EAB /* VPNConfiguration.h in Headers */,
+                               15C330C6134B92780028E36B /* rb.h in Headers */,
+                               15C330D3134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */,
+                               15D8B22C1450D8450090CECF /* SCD.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                15DAD5E1075913CE0084A6ED /* dnsinfo.h in Headers */,
+                               D661C2EF1368BB280030B977 /* network_information.h in Headers */,
                                15DAD5E2075913CE0084A6ED /* dnsinfo_private.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                                15DAD64B07591A1A0084A6ED /* SCDynamicStoreCopySpecificPrivate.h in Headers */,
                                15DAD64C07591A1A0084A6ED /* SCDynamicStoreSetSpecificPrivate.h in Headers */,
                                15DAD64D07591A1A0084A6ED /* SCPreferencesInternal.h in Headers */,
+                               7264C14614731A1F004FD76D /* CaptiveNetwork.h in Headers */,
                                15DAD64E07591A1A0084A6ED /* SCPreferences.h in Headers */,
                                15DAD64F07591A1A0084A6ED /* SCPreferencesPrivate.h in Headers */,
                                15DAD65007591A1A0084A6ED /* SCPreferencesPath.h in Headers */,
                                154CF3F407E1EA4D00D8302E /* SCPreferencesGetSpecificPrivate.h in Headers */,
                                155A1E6C081079CC00F70D98 /* SCNetworkConfigurationPrivate.h in Headers */,
                                155B7BF80847776D00F0E262 /* SCHelper_client.h in Headers */,
+                               15D8B22A1450D8450090CECF /* SCD.h in Headers */,
                                15A297300A13C08C009879B3 /* SCNetworkConnectionPrivate.h in Headers */,
                                152E68C10A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h in Headers */,
                                157A88890A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h in Headers */,
                                159A7523107FEAA400A57EAB /* VPNConfiguration.h in Headers */,
                                15AAA7F8108E310700C2A607 /* VPNTunnel.h in Headers */,
                                15AAA7F7108E310700C2A607 /* VPNTunnelPrivate.h in Headers */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               F95B8A5B0B03F81400993BA3 /* Headers */ = {
-                       isa = PBXHeadersBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
+                               15C330C4134B92780028E36B /* rb.h in Headers */,
+                               15C330D1134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        productReference = 15213FFA0E93E9F500DACD2C /* Logger.bundle */;
                        productType = "com.apple.product-type.bundle";
                };
+               1528BFDB1357305400691881 /* SCNetworkReachability */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1528BFDF1357305400691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability" */;
+                       buildPhases = (
+                               1528BFDC1357305400691881 /* Headers */,
+                               1528BFDD1357305400691881 /* Sources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = SCNetworkReachability;
+                       productName = PreferencesMonitor;
+                       productReference = 1528BFE21357305400691881 /* libSCNetworkReachability.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+               1528BFE31357309700691881 /* SCNetworkReachability.bundle */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1528BFE51357309700691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle" */;
+                       buildPhases = (
+                               1528BFE41357309700691881 /* Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = SCNetworkReachability.bundle;
+                       productInstallPath = "$(USER_LIBRARY_DIR)/Bundles";
+                       productName = PreferencesMonitor.bundle;
+                       productReference = 1528BFE81357309800691881 /* SCNetworkReachability.bundle */;
+                       productType = "com.apple.product-type.bundle";
+               };
+               1528BFF013573FEE00691881 /* SCNetworkReachability-Embedded */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1528BFF413573FEE00691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability-Embedded" */;
+                       buildPhases = (
+                               1528BFF113573FEE00691881 /* Headers */,
+                               1528BFF213573FEE00691881 /* Sources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "SCNetworkReachability-Embedded";
+                       productName = PreferencesMonitor;
+                       productReference = 1528BFF713573FEE00691881 /* libSCNetworkReachability.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+               1528BFF813573FF500691881 /* SCNetworkReachability.bundle-Embedded */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1528BFFB13573FF500691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle-Embedded" */;
+                       buildPhases = (
+                               1528BFF913573FF500691881 /* Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "SCNetworkReachability.bundle-Embedded";
+                       productInstallPath = "$(USER_LIBRARY_DIR)/Bundles";
+                       productName = PreferencesMonitor.bundle;
+                       productReference = 1528BFFE13573FF500691881 /* SCNetworkReachability.bundle */;
+                       productType = "com.apple.product-type.bundle";
+               };
+               1528BFFF1357401900691881 /* SCNetworkReachability-EmbeddedOther */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1528C0031357401900691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability-EmbeddedOther" */;
+                       buildPhases = (
+                               1528C0001357401900691881 /* Headers */,
+                               1528C0011357401900691881 /* Sources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "SCNetworkReachability-EmbeddedOther";
+                       productName = PreferencesMonitor;
+                       productReference = 1528C0061357401900691881 /* libSCNetworkReachability.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
+               1528C0071357401D00691881 /* SCNetworkReachability.bundle-EmbeddedOther */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1528C00A1357401D00691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle-EmbeddedOther" */;
+                       buildPhases = (
+                               1528C0081357401D00691881 /* Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "SCNetworkReachability.bundle-EmbeddedOther";
+                       productInstallPath = "$(USER_LIBRARY_DIR)/Bundles";
+                       productName = PreferencesMonitor.bundle;
+                       productReference = 1528C00D1357401D00691881 /* SCNetworkReachability.bundle */;
+                       productType = "com.apple.product-type.bundle";
+               };
                1547001808455B98006787CE /* SCHelper */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 156EB5E20905594A00EEF749 /* Build configuration list for PBXNativeTarget "SCHelper" */;
                        productReference = 157A852E0D56C91100B6F1A0 /* libLinkConfiguration.a */;
                        productType = "com.apple.product-type.library.static";
                };
-               157A85310D56C94F00B6F1A0 /* NetworkIdentification-Embedded */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 157A85350D56C94F00B6F1A0 /* Build configuration list for PBXNativeTarget "NetworkIdentification-Embedded" */;
-                       buildPhases = (
-                               157A85320D56C94F00B6F1A0 /* Headers */,
-                               157A85330D56C94F00B6F1A0 /* Sources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = "NetworkIdentification-Embedded";
-                       productName = NetworkIdentification;
-                       productReference = 157A85390D56C94F00B6F1A0 /* libNetworkIdentification.a */;
-                       productType = "com.apple.product-type.library.static";
-               };
                157A853C0D56C96F00B6F1A0 /* PreferencesMonitor-Embedded */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 157A85400D56C96F00B6F1A0 /* Build configuration list for PBXNativeTarget "PreferencesMonitor-Embedded" */;
                        productReference = 1559C4530D349A4E0098FD59 /* LinkConfiguration.bundle */;
                        productType = "com.apple.product-type.bundle";
                };
-               158317A00CFB8626006F62B9 /* NetworkIdentification.bundle-Embedded */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 158317A20CFB8626006F62B9 /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle-Embedded" */;
-                       buildPhases = (
-                               158317A10CFB8626006F62B9 /* Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = "NetworkIdentification.bundle-Embedded";
-                       productInstallPath = "$(USER_LIBRARY_DIR)/Bundles";
-                       productName = NetworkIdentification.bundle;
-                       productReference = 1559C4550D349A4E0098FD59 /* NetworkIdentification.bundle */;
-                       productType = "com.apple.product-type.bundle";
-               };
                158317A80CFB8639006F62B9 /* PreferencesMonitor.bundle-Embedded */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 158317AA0CFB8639006F62B9 /* Build configuration list for PBXNativeTarget "PreferencesMonitor.bundle-Embedded" */;
                        name = "DNSConfiguration-EmbeddedOther";
                        productInstallPath = /usr/local/lib/system;
                        productName = DNSConfiguration;
-                       productReference = 1583EA10108395BB00A3BC0C /* dnsinfo.dylib */;
+                       productReference = 1583EA10108395BB00A3BC0C /* libdnsinfo.dylib */;
                        productType = "com.apple.product-type.library.dynamic";
                };
                1583EA19108395BB00A3BC0C /* SystemConfiguration.framework-EmbeddedOther */ = {
                        );
                        dependencies = (
                        );
-                       name = "Logger.bundle-EmbeddedOther";
-                       productName = Logger.bundle;
-                       productReference = 1583EB21108395BC00A3BC0C /* Logger.bundle */;
-                       productType = "com.apple.product-type.bundle";
-               };
-               1583EB23108395BD00A3BC0C /* NetworkIdentification-EmbeddedOther */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 1583EB27108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "NetworkIdentification-EmbeddedOther" */;
-                       buildPhases = (
-                               1583EB24108395BD00A3BC0C /* Headers */,
-                               1583EB25108395BD00A3BC0C /* Sources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = "NetworkIdentification-EmbeddedOther";
-                       productName = NetworkIdentification;
-                       productReference = 1583EB2A108395BD00A3BC0C /* libNetworkIdentification.a */;
-                       productType = "com.apple.product-type.library.static";
-               };
-               1583EB2B108395BD00A3BC0C /* NetworkIdentification.bundle-EmbeddedOther */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 1583EB2D108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle-EmbeddedOther" */;
-                       buildPhases = (
-                               1583EB2C108395BD00A3BC0C /* Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = "NetworkIdentification.bundle-EmbeddedOther";
-                       productInstallPath = "$(USER_LIBRARY_DIR)/Bundles";
-                       productName = NetworkIdentification.bundle;
-                       productReference = 1583EB30108395BD00A3BC0C /* NetworkIdentification.bundle */;
+                       name = "Logger.bundle-EmbeddedOther";
+                       productName = Logger.bundle;
+                       productReference = 1583EB21108395BC00A3BC0C /* Logger.bundle */;
                        productType = "com.apple.product-type.bundle";
                };
                1583EB32108395BD00A3BC0C /* PreferencesMonitor-EmbeddedOther */ = {
                        productReference = 15FD72C90754DA7E001CC321 /* PreferencesMonitor.bundle */;
                        productType = "com.apple.product-type.bundle";
                };
-               F95B8A5E0B03F81400993BA3 /* NetworkIdentification */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = F95B8A610B03F83200993BA3 /* Build configuration list for PBXNativeTarget "NetworkIdentification" */;
-                       buildPhases = (
-                               F95B8A5B0B03F81400993BA3 /* Headers */,
-                               F95B8A5C0B03F81400993BA3 /* Sources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = NetworkIdentification;
-                       productName = NetworkIdentification;
-                       productReference = F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */;
-                       productType = "com.apple.product-type.library.static";
-               };
-               F95B8A6A0B03F9D100993BA3 /* NetworkIdentification.bundle */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = F95B8A6C0B03F9D100993BA3 /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle" */;
-                       buildPhases = (
-                               F95B8A6B0B03F9D100993BA3 /* Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = NetworkIdentification.bundle;
-                       productInstallPath = "$(USER_LIBRARY_DIR)/Bundles";
-                       productName = NetworkIdentification.bundle;
-                       productReference = F95B8A700B03F9D100993BA3 /* NetworkIdentification.bundle */;
-                       productType = "com.apple.product-type.bundle";
-               };
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
                15CB6A7705C0722B0099E85F /* Project object */ = {
                        isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0430;
+                       };
                        buildConfigurationList = 156EB63E0905594A00EEF749 /* Build configuration list for PBXProject "configd" */;
-                       compatibilityVersion = "Xcode 3.1";
+                       compatibilityVersion = "Xcode 3.2";
                        developmentRegion = English;
                        hasScannedForEncodings = 1;
                        knownRegions = (
                                159D53F207528C79004F8947 /* LinkConfiguration */,
                                15FD72B10754DA69001CC321 /* LinkConfiguration.bundle */,
                                15213FF90E93E9F500DACD2C /* Logger.bundle */,
-                               F95B8A5E0B03F81400993BA3 /* NetworkIdentification */,
-                               F95B8A6A0B03F9D100993BA3 /* NetworkIdentification.bundle */,
                                159D53F907528C95004F8947 /* PreferencesMonitor */,
                                15FD72C50754DA7E001CC321 /* PreferencesMonitor.bundle */,
+                               1528BFDB1357305400691881 /* SCNetworkReachability */,
+                               1528BFE31357309700691881 /* SCNetworkReachability.bundle */,
                                155847FA07550D210046C2E9 /* configd_executables */,
                                159D549F07529FFF004F8947 /* configd */,
                                1558481207550EC10046C2E9 /* scselect */,
                                157A85260D56C91100B6F1A0 /* LinkConfiguration-Embedded */,
                                158317980CFB860C006F62B9 /* LinkConfiguration.bundle-Embedded */,
                                156CA4790EF853BB00C59A18 /* Logger.bundle-Embedded */,
-                               157A85310D56C94F00B6F1A0 /* NetworkIdentification-Embedded */,
-                               158317A00CFB8626006F62B9 /* NetworkIdentification.bundle-Embedded */,
                                157A853C0D56C96F00B6F1A0 /* PreferencesMonitor-Embedded */,
                                158317A80CFB8639006F62B9 /* PreferencesMonitor.bundle-Embedded */,
+                               1528BFF013573FEE00691881 /* SCNetworkReachability-Embedded */,
+                               1528BFF813573FF500691881 /* SCNetworkReachability.bundle-Embedded */,
                                158317040CFB7782006F62B9 /* configd_executables-Embedded */,
                                158317230CFB80A1006F62B9 /* configd-Embedded */,
                                157433DD0D4A8122002ACA73 /* scselect-Embedded */,
                                1583EB07108395BC00A3BC0C /* LinkConfiguration-EmbeddedOther */,
                                1583EB0F108395BC00A3BC0C /* LinkConfiguration.bundle-EmbeddedOther */,
                                1583EB16108395BC00A3BC0C /* Logger.bundle-EmbeddedOther */,
-                               1583EB23108395BD00A3BC0C /* NetworkIdentification-EmbeddedOther */,
-                               1583EB2B108395BD00A3BC0C /* NetworkIdentification.bundle-EmbeddedOther */,
                                1583EB32108395BD00A3BC0C /* PreferencesMonitor-EmbeddedOther */,
                                1583EB3A108395BD00A3BC0C /* PreferencesMonitor.bundle-EmbeddedOther */,
+                               1528BFFF1357401900691881 /* SCNetworkReachability-EmbeddedOther */,
+                               1528C0071357401D00691881 /* SCNetworkReachability.bundle-EmbeddedOther */,
                                1583EB41108395BD00A3BC0C /* configd_executables-EmbeddedOther */,
                                1583EB4B108395BD00A3BC0C /* configd-EmbeddedOther */,
                                1583EB86108395BE00A3BC0C /* scselect-EmbeddedOther */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               1528BFE41357309700691881 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               1528BFF913573FF500691881 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               1528C0081357401D00691881 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                156CA4810EF853BB00C59A18 /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               158317A10CFB8626006F62B9 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                158317A90CFB8639006F62B9 /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               1583EB2C108395BD00A3BC0C /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                1583EB3B108395BD00A3BC0C /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               F95B8A6B0B03F9D100993BA3 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               1528BFDD1357305400691881 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               1528BFEF135733F500691881 /* SCNetworkReachabilityServer_server.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               1528BFF213573FEE00691881 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               1528BFF313573FEE00691881 /* SCNetworkReachabilityServer_server.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               1528C0011357401900691881 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               1528C0021357401900691881 /* SCNetworkReachabilityServer_server.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                1547001A08455B98006787CE /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                                1572C4E20CFB55B400E2776E /* SCDPrivate.c in Sources */,
                                1572C4E30CFB55B400E2776E /* SCDPlugin.c in Sources */,
                                1572C4E40CFB55B400E2776E /* SCDOpen.c in Sources */,
-                               1572C4E50CFB55B400E2776E /* SCDLock.c in Sources */,
-                               1572C4E60CFB55B400E2776E /* SCDUnlock.c in Sources */,
                                1572C4E70CFB55B400E2776E /* SCDList.c in Sources */,
                                1572C4E80CFB55B400E2776E /* SCDAdd.c in Sources */,
                                1572C4E90CFB55B400E2776E /* SCDGet.c in Sources */,
                                1572C4EA0CFB55B400E2776E /* SCDSet.c in Sources */,
                                1572C4EB0CFB55B400E2776E /* SCDRemove.c in Sources */,
-                               1572C4EC0CFB55B400E2776E /* SCDTouch.c in Sources */,
                                1572C4ED0CFB55B400E2776E /* SCDNotify.c in Sources */,
                                1572C4EE0CFB55B400E2776E /* SCDNotifierSetKeys.c in Sources */,
                                1572C4EF0CFB55B400E2776E /* SCDNotifierAdd.c in Sources */,
                                1572C4F10CFB55B400E2776E /* SCDNotifierGetChanges.c in Sources */,
                                1572C4F20CFB55B400E2776E /* SCDNotifierWait.c in Sources */,
                                1572C4F30CFB55B400E2776E /* SCDNotifierInformViaCallback.c in Sources */,
-                               1572C4F40CFB55B400E2776E /* SCDNotifierInformViaMachPort.c in Sources */,
                                1572C4F50CFB55B400E2776E /* SCDNotifierInformViaFD.c in Sources */,
                                1572C4F60CFB55B400E2776E /* SCDNotifierInformViaSignal.c in Sources */,
                                1572C4F70CFB55B400E2776E /* SCDNotifierCancel.c in Sources */,
                                159A7520107FEAA400A57EAB /* VPNConfiguration.c in Sources */,
                                15AAA7F6108E310700C2A607 /* VPNTunnel.c in Sources */,
                                158E595F1107CAE80062081E /* helper.defs in Sources */,
-                               152691D81129EE8A006BD2D5 /* BondConfiguration.c in Sources */,
                                152691DB1129EEA6006BD2D5 /* BridgeConfiguration.c in Sources */,
                                152691DE1129EEC2006BD2D5 /* VLANConfiguration.c in Sources */,
+                               15C330BD134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */,
+                               15C330C1134B92780028E36B /* rb.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                157A84DE0D56C63900B6F1A0 /* shared_dns_info.defs in Sources */,
                                157A84DF0D56C63900B6F1A0 /* dnsinfo_copy.c in Sources */,
                                157A84E00D56C63900B6F1A0 /* dnsinfo_private.c in Sources */,
+                               D661C2F11368BB600030B977 /* network_information.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               155281020E3E4A0F00C54315 /* ip_plugin.c in Sources */,
                                157A84FB0D56C7E800B6F1A0 /* dns-configuration.c in Sources */,
+                               15D48EC10F67061F00B4711E /* dnsinfo_create.c in Sources */,
+                               155281020E3E4A0F00C54315 /* ip_plugin.c in Sources */,
+                               E4F211D3137B0AB900BBB915 /* network_information_priv.c in Sources */,
                                1575FD2712CD15C60003D86E /* proxy-configuration.c in Sources */,
                                157A84FC0D56C7E800B6F1A0 /* set-hostname.c in Sources */,
-                               15D48EC10F67061F00B4711E /* dnsinfo_create.c in Sources */,
                                15D48ED40F6707A600B4711E /* shared_dns_info.defs in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               157A85330D56C94F00B6F1A0 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               157A85340D56C94F00B6F1A0 /* NetworkIdentification.c in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                157A853E0D56C96F00B6F1A0 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                                158317330CFB80A1006F62B9 /* pattern.c in Sources */,
                                158317340CFB80A1006F62B9 /* _configopen.c in Sources */,
                                158317350CFB80A1006F62B9 /* _configclose.c in Sources */,
-                               158317360CFB80A1006F62B9 /* _configlock.c in Sources */,
                                158317370CFB80A1006F62B9 /* _configunlock.c in Sources */,
                                158317380CFB80A1006F62B9 /* _configlist.c in Sources */,
                                158317390CFB80A1006F62B9 /* _configadd.c in Sources */,
                                1583173A0CFB80A1006F62B9 /* _configget.c in Sources */,
                                1583173B0CFB80A1006F62B9 /* _configset.c in Sources */,
                                1583173C0CFB80A1006F62B9 /* _configremove.c in Sources */,
-                               1583173D0CFB80A1006F62B9 /* _configtouch.c in Sources */,
                                1583173E0CFB80A1006F62B9 /* _confignotify.c in Sources */,
                                1583173F0CFB80A1006F62B9 /* _notifyadd.c in Sources */,
                                158317400CFB80A1006F62B9 /* _notifyremove.c in Sources */,
                                158317480CFB80A1006F62B9 /* dnsinfo_private.c in Sources */,
                                158317490CFB80A1006F62B9 /* dnsinfo_server.c in Sources */,
                                1583174A0CFB80A1006F62B9 /* shared_dns_info.defs in Sources */,
+                               15C330E5134BD2AC0028E36B /* SCNetworkReachabilityServer_server.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                1583EA09108395BB00A3BC0C /* shared_dns_info.defs in Sources */,
                                1583EA0A108395BB00A3BC0C /* dnsinfo_copy.c in Sources */,
                                1583EA0B108395BB00A3BC0C /* dnsinfo_private.c in Sources */,
+                               151E0CA51378EE3B00C5DA2A /* network_information.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                1583EA53108395BB00A3BC0C /* SCDPrivate.c in Sources */,
                                1583EA54108395BB00A3BC0C /* SCDPlugin.c in Sources */,
                                1583EA55108395BB00A3BC0C /* SCDOpen.c in Sources */,
-                               1583EA56108395BB00A3BC0C /* SCDLock.c in Sources */,
-                               1583EA57108395BB00A3BC0C /* SCDUnlock.c in Sources */,
                                1583EA58108395BB00A3BC0C /* SCDList.c in Sources */,
                                1583EA59108395BB00A3BC0C /* SCDAdd.c in Sources */,
                                1583EA5A108395BB00A3BC0C /* SCDGet.c in Sources */,
                                1583EA5B108395BB00A3BC0C /* SCDSet.c in Sources */,
                                1583EA5C108395BB00A3BC0C /* SCDRemove.c in Sources */,
-                               1583EA5D108395BB00A3BC0C /* SCDTouch.c in Sources */,
                                1583EA5E108395BB00A3BC0C /* SCDNotify.c in Sources */,
                                1583EA5F108395BB00A3BC0C /* SCDNotifierSetKeys.c in Sources */,
                                1583EA60108395BB00A3BC0C /* SCDNotifierAdd.c in Sources */,
                                1583EA62108395BB00A3BC0C /* SCDNotifierGetChanges.c in Sources */,
                                1583EA63108395BB00A3BC0C /* SCDNotifierWait.c in Sources */,
                                1583EA64108395BB00A3BC0C /* SCDNotifierInformViaCallback.c in Sources */,
-                               1583EA65108395BB00A3BC0C /* SCDNotifierInformViaMachPort.c in Sources */,
                                1583EA66108395BB00A3BC0C /* SCDNotifierInformViaFD.c in Sources */,
                                1583EA67108395BB00A3BC0C /* SCDNotifierInformViaSignal.c in Sources */,
                                1583EA68108395BB00A3BC0C /* SCDNotifierCancel.c in Sources */,
                                1583EA8E108395BB00A3BC0C /* SCNetworkSignature.c in Sources */,
                                1583EA8F108395BB00A3BC0C /* CaptiveNetwork.c in Sources */,
                                158E59601107CAF10062081E /* helper.defs in Sources */,
-                               152691D91129EE94006BD2D5 /* BondConfiguration.c in Sources */,
                                152691DD1129EEB1006BD2D5 /* BridgeConfiguration.c in Sources */,
                                152691E01129EECB006BD2D5 /* VLANConfiguration.c in Sources */,
+                               15C330BF134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */,
+                               15C330C3134B92780028E36B /* rb.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               1583EAD0108395BB00A3BC0C /* ip_plugin.c in Sources */,
                                1583EAD1108395BB00A3BC0C /* dns-configuration.c in Sources */,
+                               1583EAD3108395BB00A3BC0C /* dnsinfo_create.c in Sources */,
+                               1583EAD0108395BB00A3BC0C /* ip_plugin.c in Sources */,
+                               E4F211D5137B0AD700BBB915 /* network_information_priv.c in Sources */,
                                1575FD2B12CD15C60003D86E /* proxy-configuration.c in Sources */,
                                1583EAD2108395BB00A3BC0C /* set-hostname.c in Sources */,
-                               1583EAD3108395BB00A3BC0C /* dnsinfo_create.c in Sources */,
                                1583EAD4108395BB00A3BC0C /* shared_dns_info.defs in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               1583EB25108395BD00A3BC0C /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               1583EB26108395BD00A3BC0C /* NetworkIdentification.c in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                1583EB34108395BD00A3BC0C /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                                1583EB5B108395BD00A3BC0C /* pattern.c in Sources */,
                                1583EB5C108395BD00A3BC0C /* _configopen.c in Sources */,
                                1583EB5D108395BD00A3BC0C /* _configclose.c in Sources */,
-                               1583EB5E108395BD00A3BC0C /* _configlock.c in Sources */,
                                1583EB5F108395BD00A3BC0C /* _configunlock.c in Sources */,
                                1583EB60108395BD00A3BC0C /* _configlist.c in Sources */,
                                1583EB61108395BD00A3BC0C /* _configadd.c in Sources */,
                                1583EB62108395BD00A3BC0C /* _configget.c in Sources */,
                                1583EB63108395BD00A3BC0C /* _configset.c in Sources */,
                                1583EB64108395BD00A3BC0C /* _configremove.c in Sources */,
-                               1583EB65108395BD00A3BC0C /* _configtouch.c in Sources */,
                                1583EB66108395BD00A3BC0C /* _confignotify.c in Sources */,
                                1583EB67108395BD00A3BC0C /* _notifyadd.c in Sources */,
                                1583EB68108395BD00A3BC0C /* _notifyremove.c in Sources */,
                                1583EB70108395BD00A3BC0C /* dnsinfo_private.c in Sources */,
                                1583EB71108395BD00A3BC0C /* dnsinfo_server.c in Sources */,
                                1583EB72108395BD00A3BC0C /* shared_dns_info.defs in Sources */,
+                               15C330E6134BD2BB0028E36B /* SCNetworkReachabilityServer_server.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               159D541707528E05004F8947 /* ip_plugin.c in Sources */,
                                159D541807528E09004F8947 /* dns-configuration.c in Sources */,
+                               15D48EBF0F67061600B4711E /* dnsinfo_create.c in Sources */,
+                               1522FCFB0FA7FE4B00B24128 /* dnsinfo_flatfile.c in Sources */,
+                               159D541707528E05004F8947 /* ip_plugin.c in Sources */,
+                               E49173E1137C4E4F0000089F /* network_information_priv.c in Sources */,
                                1575FD2912CD15C60003D86E /* proxy-configuration.c in Sources */,
                                154361E00752C81800A8EC6C /* set-hostname.c in Sources */,
                                1572EB7B0A506D3B00D02459 /* smb-configuration.c in Sources */,
-                               15D48EBF0F67061600B4711E /* dnsinfo_create.c in Sources */,
                                15D48ED30F67079B00B4711E /* shared_dns_info.defs in Sources */,
-                               1522FCFB0FA7FE4B00B24128 /* dnsinfo_flatfile.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                159D54B207529FFF004F8947 /* pattern.c in Sources */,
                                159D54B307529FFF004F8947 /* _configopen.c in Sources */,
                                159D54B407529FFF004F8947 /* _configclose.c in Sources */,
-                               159D54B507529FFF004F8947 /* _configlock.c in Sources */,
                                159D54B607529FFF004F8947 /* _configunlock.c in Sources */,
                                159D54B707529FFF004F8947 /* _configlist.c in Sources */,
                                159D54B807529FFF004F8947 /* _configadd.c in Sources */,
                                159D54B907529FFF004F8947 /* _configget.c in Sources */,
                                159D54BA07529FFF004F8947 /* _configset.c in Sources */,
                                159D54BB07529FFF004F8947 /* _configremove.c in Sources */,
-                               159D54BC07529FFF004F8947 /* _configtouch.c in Sources */,
                                159D54BD07529FFF004F8947 /* _confignotify.c in Sources */,
                                159D54BE07529FFF004F8947 /* _notifyadd.c in Sources */,
                                159D54BF07529FFF004F8947 /* _notifyremove.c in Sources */,
                                15A5A2210D5B94190087BDA0 /* SCDPrivate.c in Sources */,
                                15A5A2220D5B94190087BDA0 /* SCDPlugin.c in Sources */,
                                15A5A2230D5B94190087BDA0 /* SCDOpen.c in Sources */,
-                               15A5A2240D5B94190087BDA0 /* SCDLock.c in Sources */,
-                               15A5A2250D5B94190087BDA0 /* SCDUnlock.c in Sources */,
                                15A5A2260D5B94190087BDA0 /* SCDList.c in Sources */,
                                15A5A2270D5B94190087BDA0 /* SCDAdd.c in Sources */,
                                15A5A2280D5B94190087BDA0 /* SCDGet.c in Sources */,
                                15A5A2290D5B94190087BDA0 /* SCDSet.c in Sources */,
                                15A5A22A0D5B94190087BDA0 /* SCDRemove.c in Sources */,
-                               15A5A22B0D5B94190087BDA0 /* SCDTouch.c in Sources */,
                                15A5A22C0D5B94190087BDA0 /* SCDNotify.c in Sources */,
                                15A5A22D0D5B94190087BDA0 /* SCDNotifierSetKeys.c in Sources */,
                                15A5A22E0D5B94190087BDA0 /* SCDNotifierAdd.c in Sources */,
                                15A5A2300D5B94190087BDA0 /* SCDNotifierGetChanges.c in Sources */,
                                15A5A2310D5B94190087BDA0 /* SCDNotifierWait.c in Sources */,
                                15A5A2320D5B94190087BDA0 /* SCDNotifierInformViaCallback.c in Sources */,
-                               15A5A2330D5B94190087BDA0 /* SCDNotifierInformViaMachPort.c in Sources */,
                                15A5A2340D5B94190087BDA0 /* SCDNotifierInformViaFD.c in Sources */,
                                15A5A2350D5B94190087BDA0 /* SCDNotifierInformViaSignal.c in Sources */,
                                15A5A2360D5B94190087BDA0 /* SCDNotifierCancel.c in Sources */,
                                159A752C107FEAA400A57EAB /* VPNPrivate.c in Sources */,
                                159A752E107FEAA400A57EAB /* VPNConfiguration.c in Sources */,
                                158E59611107CAF40062081E /* helper.defs in Sources */,
-                               152691DA1129EE98006BD2D5 /* BondConfiguration.c in Sources */,
                                152691DC1129EEAD006BD2D5 /* BridgeConfiguration.c in Sources */,
                                152691DF1129EEC8006BD2D5 /* VLANConfiguration.c in Sources */,
+                               15C330BE134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */,
+                               15C330C2134B92780028E36B /* rb.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                15DAD5E5075913CE0084A6ED /* shared_dns_info.defs in Sources */,
                                15DAD5E6075913CE0084A6ED /* dnsinfo_copy.c in Sources */,
                                15DAD5E7075913CE0084A6ED /* dnsinfo_private.c in Sources */,
+                               D6986A79136891650091C931 /* network_information.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                15DAD66E07591A1A0084A6ED /* SCDKeys.c in Sources */,
                                15DAD66F07591A1A0084A6ED /* SCDPrivate.c in Sources */,
                                15DAD67007591A1A0084A6ED /* SCDPlugin.c in Sources */,
+                               7264C144147319E7004FD76D /* CaptiveNetwork.c in Sources */,
                                15DAD67107591A1A0084A6ED /* SCDOpen.c in Sources */,
-                               15DAD67207591A1A0084A6ED /* SCDLock.c in Sources */,
-                               15DAD67307591A1A0084A6ED /* SCDUnlock.c in Sources */,
                                15DAD67407591A1A0084A6ED /* SCDList.c in Sources */,
                                15DAD67507591A1A0084A6ED /* SCDAdd.c in Sources */,
                                15DAD67607591A1A0084A6ED /* SCDGet.c in Sources */,
                                15DAD67707591A1A0084A6ED /* SCDSet.c in Sources */,
                                15DAD67807591A1A0084A6ED /* SCDRemove.c in Sources */,
-                               15DAD67907591A1A0084A6ED /* SCDTouch.c in Sources */,
                                15DAD67A07591A1A0084A6ED /* SCDNotify.c in Sources */,
                                15DAD67B07591A1A0084A6ED /* SCDNotifierSetKeys.c in Sources */,
                                15DAD67C07591A1A0084A6ED /* SCDNotifierAdd.c in Sources */,
                                15DAD67E07591A1A0084A6ED /* SCDNotifierGetChanges.c in Sources */,
                                15DAD67F07591A1A0084A6ED /* SCDNotifierWait.c in Sources */,
                                15DAD68007591A1A0084A6ED /* SCDNotifierInformViaCallback.c in Sources */,
-                               15DAD68107591A1A0084A6ED /* SCDNotifierInformViaMachPort.c in Sources */,
                                15DAD68207591A1A0084A6ED /* SCDNotifierInformViaFD.c in Sources */,
                                15DAD68307591A1A0084A6ED /* SCDNotifierInformViaSignal.c in Sources */,
                                15DAD68407591A1A0084A6ED /* SCDNotifierCancel.c in Sources */,
                                159A7527107FEAA400A57EAB /* VPNConfiguration.c in Sources */,
                                15AAA7F9108E310700C2A607 /* VPNTunnel.c in Sources */,
                                158E595E1107CAE40062081E /* helper.defs in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               F95B8A5C0B03F81400993BA3 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               F95B8A690B03F9B500993BA3 /* NetworkIdentification.c in Sources */,
+                               15C330BC134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */,
+                               15C330C0134B92780028E36B /* rb.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        target = 151FE2DD0D5B7046000D6DB1 /* configd_base-EmbeddedSimulator */;
                        targetProxy = 151FE3790D5B713C000D6DB1 /* PBXContainerItemProxy */;
                };
-               1520A386084681350010B584 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 1547001808455B98006787CE /* SCHelper */;
-                       targetProxy = 1520A385084681350010B584 /* PBXContainerItemProxy */;
-               };
                1521405B0E9400BF00DACD2C /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 15213FF90E93E9F500DACD2C /* Logger.bundle */;
                        targetProxy = 1521405A0E9400BF00DACD2C /* PBXContainerItemProxy */;
                };
+               1528BFEC135731B800691881 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 1528BFDB1357305400691881 /* SCNetworkReachability */;
+                       targetProxy = 1528BFEB135731B800691881 /* PBXContainerItemProxy */;
+               };
+               1528BFEE135731B800691881 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 1528BFE31357309700691881 /* SCNetworkReachability.bundle */;
+                       targetProxy = 1528BFED135731B800691881 /* PBXContainerItemProxy */;
+               };
+               1528C00F135741C300691881 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 1528BFF013573FEE00691881 /* SCNetworkReachability-Embedded */;
+                       targetProxy = 1528C00E135741C300691881 /* PBXContainerItemProxy */;
+               };
+               1528C011135741C300691881 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 1528BFF813573FF500691881 /* SCNetworkReachability.bundle-Embedded */;
+                       targetProxy = 1528C010135741C300691881 /* PBXContainerItemProxy */;
+               };
+               1528C0131357420300691881 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 1528BFFF1357401900691881 /* SCNetworkReachability-EmbeddedOther */;
+                       targetProxy = 1528C0121357420300691881 /* PBXContainerItemProxy */;
+               };
+               1528C0151357420300691881 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 1528C0071357401D00691881 /* SCNetworkReachability.bundle-EmbeddedOther */;
+                       targetProxy = 1528C0141357420300691881 /* PBXContainerItemProxy */;
+               };
                1558480607550D470046C2E9 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 159D549F07529FFF004F8947 /* configd */;
                        target = 157A85260D56C91100B6F1A0 /* LinkConfiguration-Embedded */;
                        targetProxy = 157A854D0D56CA6F00B6F1A0 /* PBXContainerItemProxy */;
                };
-               157A85500D56CA8800B6F1A0 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 157A85310D56C94F00B6F1A0 /* NetworkIdentification-Embedded */;
-                       targetProxy = 157A854F0D56CA8800B6F1A0 /* PBXContainerItemProxy */;
-               };
                157A85520D56CA9E00B6F1A0 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 157A853C0D56C96F00B6F1A0 /* PreferencesMonitor-Embedded */;
                        target = 158317230CFB80A1006F62B9 /* configd-Embedded */;
                        targetProxy = 158317650CFB80D5006F62B9 /* PBXContainerItemProxy */;
                };
-               158317B30CFB8660006F62B9 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 158317A00CFB8626006F62B9 /* NetworkIdentification.bundle-Embedded */;
-                       targetProxy = 158317B20CFB8660006F62B9 /* PBXContainerItemProxy */;
-               };
                158317B50CFB8660006F62B9 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 158317980CFB860C006F62B9 /* LinkConfiguration.bundle-Embedded */;
                        target = 1583EB32108395BD00A3BC0C /* PreferencesMonitor-EmbeddedOther */;
                        targetProxy = 15AC5172108396D2004A9ED5 /* PBXContainerItemProxy */;
                };
-               15AC5175108396D2004A9ED5 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 1583EB2B108395BD00A3BC0C /* NetworkIdentification.bundle-EmbeddedOther */;
-                       targetProxy = 15AC5174108396D2004A9ED5 /* PBXContainerItemProxy */;
-               };
-               15AC5177108396D2004A9ED5 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 1583EB23108395BD00A3BC0C /* NetworkIdentification-EmbeddedOther */;
-                       targetProxy = 15AC5176108396D2004A9ED5 /* PBXContainerItemProxy */;
-               };
                15AC5179108396D2004A9ED5 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 1583EB16108395BC00A3BC0C /* Logger.bundle-EmbeddedOther */;
                        target = 157A84D80D56C63900B6F1A0 /* DNSConfiguration-Embedded */;
                        targetProxy = 15C64A300F684C8F00D78394 /* PBXContainerItemProxy */;
                };
-               F95B8A770B03FB9100993BA3 /* PBXTargetDependency */ = {
+               D6DDAC3D147A24BC00A2E902 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = F95B8A6A0B03F9D100993BA3 /* NetworkIdentification.bundle */;
-                       targetProxy = F95B8A760B03FB9100993BA3 /* PBXContainerItemProxy */;
-               };
-               F95B8A790B03FB9100993BA3 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = F95B8A5E0B03F81400993BA3 /* NetworkIdentification */;
-                       targetProxy = F95B8A780B03FB9100993BA3 /* PBXContainerItemProxy */;
+                       target = 1547001808455B98006787CE /* SCHelper */;
+                       targetProxy = D6DDAC3C147A24BC00A2E902 /* PBXContainerItemProxy */;
                };
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
                151C1CC70CFB487000C5AFD6 /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd (Aggregate/Embedded)";
                        };
                };
                151C1CC80CFB487000C5AFD6 /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd (Aggregate/Embedded)";
                        };
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
                                INFOPLIST_FILE = SCMonitor/Info.plist;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = /System/Library/UserEventPlugins;
-                               PRODUCT_NAME = SCMonitor;
-                               WRAPPER_EXTENSION = plugin;
+                               INSTALL_PATH = /System/Library/UserEventPlugins;
+                               PRODUCT_NAME = SCMonitor;
+                               WRAPPER_EXTENSION = plugin;
+                       };
+                       name = Release;
+               };
+               151F63DD09328A3C0096DCC9 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               INSTALLHDRS_SCRIPT_PHASE = YES;
+                               PRODUCT_NAME = genSCPreferences;
+                               WARNING_CFLAGS = (
+                                       "-Wall",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Debug;
+               };
+               151F63DE09328A3C0096DCC9 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               INSTALLHDRS_SCRIPT_PHASE = YES;
+                               PRODUCT_NAME = genSCPreferences;
+                               WARNING_CFLAGS = (
+                                       "-Wall",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Release;
+               };
+               151FE2E50D5B7046000D6DB1 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */;
+                       buildSettings = {
+                               PRODUCT_NAME = "configd_base (EmbeddedSimulator)";
+                       };
+                       name = Debug;
+               };
+               151FE2E60D5B7046000D6DB1 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */;
+                       buildSettings = {
+                               PRODUCT_NAME = "configd_base (EmbeddedSimulator)";
+                       };
+                       name = Release;
+               };
+               15213FFC0E93E9F600DACD2C /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               INFOPLIST_FILE = Plugins/Logger/Info.plist;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
+                               PRODUCT_NAME = Logger;
+                       };
+                       name = Debug;
+               };
+               15213FFD0E93E9F600DACD2C /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               INFOPLIST_FILE = Plugins/Logger/Info.plist;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
+                               PRODUCT_NAME = Logger;
+                       };
+                       name = Release;
+               };
+               1528BFE01357305400691881 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
+                               LIBRARY_STYLE = STATIC;
+                               PRODUCT_NAME = SCNetworkReachability;
+                               STRIP_INSTALLED_PRODUCT = NO;
+                       };
+                       name = Debug;
+               };
+               1528BFE11357305400691881 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
+                               LIBRARY_STYLE = STATIC;
+                               PRODUCT_NAME = SCNetworkReachability;
+                               STRIP_INSTALLED_PRODUCT = NO;
+                       };
+                       name = Release;
+               };
+               1528BFE61357309700691881 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
+                               PRODUCT_NAME = SCNetworkReachability;
+                       };
+                       name = Debug;
+               };
+               1528BFE71357309700691881 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
+                               PRODUCT_NAME = SCNetworkReachability;
+                       };
+                       name = Release;
+               };
+               1528BFF513573FEE00691881 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
+                       buildSettings = {
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
+                               LIBRARY_STYLE = STATIC;
+                               PRODUCT_NAME = SCNetworkReachability;
+                               STRIP_INSTALLED_PRODUCT = NO;
+                       };
+                       name = Debug;
+               };
+               1528BFF613573FEE00691881 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
+                       buildSettings = {
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
+                               LIBRARY_STYLE = STATIC;
+                               PRODUCT_NAME = SCNetworkReachability;
+                               STRIP_INSTALLED_PRODUCT = NO;
                        };
                        name = Release;
                };
-               151F63DD09328A3C0096DCC9 /* Debug */ = {
+               1528BFFC13573FF500691881 /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               INSTALLHDRS_SCRIPT_PHASE = YES;
-                               PRODUCT_NAME = genSCPreferences;
-                               WARNING_CFLAGS = (
-                                       "-Wall",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
+                               INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
+                               PRODUCT_NAME = SCNetworkReachability;
                        };
                        name = Debug;
                };
-               151F63DE09328A3C0096DCC9 /* Release */ = {
+               1528BFFD13573FF500691881 /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                               INSTALLHDRS_SCRIPT_PHASE = YES;
-                               PRODUCT_NAME = genSCPreferences;
-                               WARNING_CFLAGS = (
-                                       "-Wall",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                               );
+                               INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
+                               PRODUCT_NAME = SCNetworkReachability;
                        };
                        name = Release;
                };
-               151FE2E50D5B7046000D6DB1 /* Debug */ = {
+               1528C0041357401900691881 /* Debug */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
-                               PRODUCT_NAME = "configd_base (EmbeddedSimulator)";
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
+                               LIBRARY_STYLE = STATIC;
+                               PRODUCT_NAME = SCNetworkReachability;
+                               STRIP_INSTALLED_PRODUCT = NO;
                        };
                        name = Debug;
                };
-               151FE2E60D5B7046000D6DB1 /* Release */ = {
+               1528C0051357401900691881 /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
-                               PRODUCT_NAME = "configd_base (EmbeddedSimulator)";
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               INSTALL_MODE_FLAG = "a-w,a+rX";
+                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
+                               LIBRARY_STYLE = STATIC;
+                               PRODUCT_NAME = SCNetworkReachability;
+                               STRIP_INSTALLED_PRODUCT = NO;
                        };
                        name = Release;
                };
-               15213FFC0E93E9F600DACD2C /* Debug */ = {
+               1528C00B1357401D00691881 /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
-                               INFOPLIST_FILE = Plugins/Logger/Info.plist;
+                               INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
-                               PRODUCT_NAME = Logger;
+                               PRODUCT_NAME = SCNetworkReachability;
                        };
                        name = Debug;
                };
-               15213FFD0E93E9F600DACD2C /* Release */ = {
+               1528C00C1357401D00691881 /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
-                               INFOPLIST_FILE = Plugins/Logger/Info.plist;
+                               INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
-                               PRODUCT_NAME = Logger;
+                               PRODUCT_NAME = SCNetworkReachability;
                        };
                        name = Release;
                };
                                INSTALLHDRS_COPY_PHASE = YES;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/lib/system;
+                               LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib;
                                MACH_O_TYPE = mh_dylib;
                                OTHER_CFLAGS_debug = "-O0";
                                OTHER_LDFLAGS = (
                                INSTALLHDRS_COPY_PHASE = YES;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/lib/system;
+                               LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib;
                                MACH_O_TYPE = mh_dylib;
                                OTHER_CFLAGS_debug = "-O0";
                                OTHER_CFLAGS_normal = "";
                        buildSettings = {
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/SystemConfiguration.framework/Versions/A/Resources";
                                PRODUCT_NAME = SCHelper;
                        buildSettings = {
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/SystemConfiguration.framework/Versions/A/Resources";
                                PRODUCT_NAME = SCHelper;
                        buildSettings = {
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/libexec;
                                LIBRARY_SEARCH_PATHS = (
                        buildSettings = {
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/libexec;
                                LIBRARY_SEARCH_PATHS = (
                        buildSettings = {
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_MODE_FLAG = "a-w,a+rX,u+s";
                                INSTALL_PATH = /usr/sbin;
                                PRODUCT_NAME = scselect;
                        buildSettings = {
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_MODE_FLAG = "a-w,a+rX,u+s";
                                INSTALL_PATH = /usr/sbin;
                                PRODUCT_NAME = scselect;
                        buildSettings = {
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = (
                        buildSettings = {
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)";
+                               GCC_DYNAMIC_NO_PIC = NO;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = (
                156EB63F0905594A00EEF749 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "ARCHS[sdk=iphoneos*]" = "$(NATIVE_ARCH)";
+                               "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_32_64_BIT)";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                DYLIB_COMPATIBILITY_VERSION = 1;
                                DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
                                GCC_OPTIMIZATION_LEVEL = 0;
                                        "-Wno-four-char-constants",
                                        "-Wno-unknown-pragmas",
                                        "-Wformat-security",
+                                       "-Wcast-align",
                                );
                        };
                        name = Debug;
                                        "-Wno-four-char-constants",
                                        "-Wno-unknown-pragmas",
                                        "-Wformat-security",
+                                       "-Wcast-align",
                                );
                        };
                        name = Release;
                                INSTALLHDRS_COPY_PHASE = YES;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/lib/system;
+                               LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib;
                                MACH_O_TYPE = mh_dylib;
                                OTHER_CFLAGS_debug = "-O0";
                                OTHER_CFLAGS_normal = "";
                                INSTALLHDRS_COPY_PHASE = YES;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/lib/system;
+                               LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib;
                                MACH_O_TYPE = mh_dylib;
                                OTHER_CFLAGS_debug = "-O0";
                                OTHER_CFLAGS_normal = "";
                        };
                        name = Release;
                };
-               157A85360D56C94F00B6F1A0 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
-                               LIBRARY_STYLE = STATIC;
-                               PRODUCT_NAME = NetworkIdentification;
-                               STRIP_INSTALLED_PRODUCT = NO;
-                       };
-                       name = Debug;
-               };
-               157A85370D56C94F00B6F1A0 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
-                               LIBRARY_STYLE = STATIC;
-                               PRODUCT_NAME = NetworkIdentification;
-                               STRIP_INSTALLED_PRODUCT = NO;
-                       };
-                       name = Release;
-               };
                157A85410D56C96F00B6F1A0 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                };
                158316D90CFB774B006F62B9 /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_base (Embedded)";
                        };
                };
                158316DA0CFB774B006F62B9 /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_base (Embedded)";
                        };
                };
                158317010CFB7761006F62B9 /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_plugins (Embedded)";
                        };
                };
                158317020CFB7761006F62B9 /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_plugins (Embedded)";
                        };
                };
                1583170C0CFB7782006F62B9 /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_executables (Embedded)";
                        };
                };
                1583170D0CFB7782006F62B9 /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_executables (Embedded)";
                        };
                        };
                        name = Release;
                };
-               158317A30CFB8626006F62B9 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
-                       buildSettings = {
-                               INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
-                               PRODUCT_NAME = NetworkIdentification;
-                       };
-                       name = Debug;
-               };
-               158317A40CFB8626006F62B9 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
-                       buildSettings = {
-                               INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
-                               PRODUCT_NAME = NetworkIdentification;
-                       };
-                       name = Release;
-               };
                158317AB0CFB8639006F62B9 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                };
                1583E9EA1083959E00A3BC0C /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd (Aggregate/EmbeddedOther)";
                        };
                };
                1583E9EB1083959E00A3BC0C /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd (Aggregate/EmbeddedOther)";
                        };
                                INSTALLHDRS_COPY_PHASE = YES;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/lib/system;
+                               LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib;
                                MACH_O_TYPE = mh_dylib;
                                OTHER_CFLAGS_debug = "-O0";
                                OTHER_CFLAGS_normal = "";
                                        System,
                                );
                                OTHER_MIGFLAGS = "-DLIBDNSINFO";
-                               PRODUCT_NAME = dnsinfo;
+                               PRODUCT_NAME = libdnsinfo;
                                STRIP_INSTALLED_PRODUCT_debug = NO;
                                STRIP_INSTALLED_PRODUCT_normal = YES;
                                STRIP_INSTALLED_PRODUCT_profile = NO;
                                INSTALLHDRS_COPY_PHASE = YES;
                                INSTALL_MODE_FLAG = "a-w,a+rX";
                                INSTALL_PATH = /usr/lib/system;
+                               LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib;
                                MACH_O_TYPE = mh_dylib;
                                OTHER_CFLAGS_debug = "-O0";
                                OTHER_CFLAGS_normal = "";
                                        System,
                                );
                                OTHER_MIGFLAGS = "-DLIBDNSINFO";
-                               PRODUCT_NAME = dnsinfo;
+                               PRODUCT_NAME = libdnsinfo;
                                STRIP_INSTALLED_PRODUCT_debug = NO;
                                STRIP_INSTALLED_PRODUCT_normal = YES;
                                STRIP_INSTALLED_PRODUCT_profile = NO;
                };
                1583EA17108395BB00A3BC0C /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_base (EmbeddedOther)";
                        };
                };
                1583EA18108395BB00A3BC0C /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_base (EmbeddedOther)";
                        };
                };
                1583EAC8108395BB00A3BC0C /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_plugins (EmbeddedOther)";
                        };
                };
                1583EAC9108395BB00A3BC0C /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_plugins (EmbeddedOther)";
                        };
                        };
                        name = Release;
                };
-               1583EB28108395BD00A3BC0C /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
-                               LIBRARY_STYLE = STATIC;
-                               PRODUCT_NAME = NetworkIdentification;
-                               STRIP_INSTALLED_PRODUCT = NO;
-                       };
-                       name = Debug;
-               };
-               1583EB29108395BD00A3BC0C /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
-                               LIBRARY_STYLE = STATIC;
-                               PRODUCT_NAME = NetworkIdentification;
-                               STRIP_INSTALLED_PRODUCT = NO;
-                       };
-                       name = Release;
-               };
-               1583EB2E108395BD00A3BC0C /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
-                       buildSettings = {
-                               INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
-                               PRODUCT_NAME = NetworkIdentification;
-                       };
-                       name = Debug;
-               };
-               1583EB2F108395BD00A3BC0C /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
-                       buildSettings = {
-                               INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
-                               PRODUCT_NAME = NetworkIdentification;
-                       };
-                       name = Release;
-               };
                1583EB37108395BD00A3BC0C /* Debug */ = {
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                };
                1583EB49108395BD00A3BC0C /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_executables (EmbeddedOther)";
                        };
                };
                1583EB4A108395BD00A3BC0C /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */;
                        buildSettings = {
                                PRODUCT_NAME = "configd_executables (EmbeddedOther)";
                        };
                        };
                        name = Release;
                };
-               F95B8A620B03F83200993BA3 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
-                               LIBRARY_STYLE = STATIC;
-                               PRODUCT_NAME = NetworkIdentification;
-                               STRIP_INSTALLED_PRODUCT = NO;
-                       };
-                       name = Debug;
-               };
-               F95B8A630B03F83200993BA3 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = /usr/local/lib/SystemConfiguration;
-                               LIBRARY_STYLE = STATIC;
-                               PRODUCT_NAME = NetworkIdentification;
-                               STRIP_INSTALLED_PRODUCT = NO;
-                       };
-                       name = Release;
-               };
-               F95B8A6D0B03F9D100993BA3 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
-                               PRODUCT_NAME = NetworkIdentification;
-                       };
-                       name = Debug;
-               };
-               F95B8A6E0B03F9D100993BA3 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist;
-                               INSTALL_MODE_FLAG = "a-w,a+rX";
-                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration";
-                               PRODUCT_NAME = NetworkIdentification;
-                       };
-                       name = Release;
-               };
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               1528BFDF1357305400691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1528BFE01357305400691881 /* Debug */,
+                               1528BFE11357305400691881 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               1528BFE51357309700691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1528BFE61357309700691881 /* Debug */,
+                               1528BFE71357309700691881 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               1528BFF413573FEE00691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability-Embedded" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1528BFF513573FEE00691881 /* Debug */,
+                               1528BFF613573FEE00691881 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               1528BFFB13573FF500691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle-Embedded" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1528BFFC13573FF500691881 /* Debug */,
+                               1528BFFD13573FF500691881 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               1528C0031357401900691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability-EmbeddedOther" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1528C0041357401900691881 /* Debug */,
+                               1528C0051357401900691881 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               1528C00A1357401D00691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle-EmbeddedOther" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1528C00B1357401D00691881 /* Debug */,
+                               1528C00C1357401D00691881 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                156CA4820EF853BB00C59A18 /* Build configuration list for PBXNativeTarget "Logger.bundle-Embedded" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               157A85350D56C94F00B6F1A0 /* Build configuration list for PBXNativeTarget "NetworkIdentification-Embedded" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               157A85360D56C94F00B6F1A0 /* Debug */,
-                               157A85370D56C94F00B6F1A0 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
                157A85400D56C96F00B6F1A0 /* Build configuration list for PBXNativeTarget "PreferencesMonitor-Embedded" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               158317A20CFB8626006F62B9 /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle-Embedded" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               158317A30CFB8626006F62B9 /* Debug */,
-                               158317A40CFB8626006F62B9 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
                158317AA0CFB8639006F62B9 /* Build configuration list for PBXNativeTarget "PreferencesMonitor.bundle-Embedded" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               1583EB27108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "NetworkIdentification-EmbeddedOther" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               1583EB28108395BD00A3BC0C /* Debug */,
-                               1583EB29108395BD00A3BC0C /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               1583EB2D108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle-EmbeddedOther" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               1583EB2E108395BD00A3BC0C /* Debug */,
-                               1583EB2F108395BD00A3BC0C /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
                1583EB36108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "PreferencesMonitor-EmbeddedOther" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               F95B8A610B03F83200993BA3 /* Build configuration list for PBXNativeTarget "NetworkIdentification" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               F95B8A620B03F83200993BA3 /* Debug */,
-                               F95B8A630B03F83200993BA3 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
-               F95B8A6C0B03F9D100993BA3 /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               F95B8A6D0B03F9D100993BA3 /* Debug */,
-                               F95B8A6E0B03F9D100993BA3 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
 /* End XCConfigurationList section */
        };
        rootObject = 15CB6A7705C0722B0099E85F /* Project object */;
index 870030528c90a0070824ab30b7977ecaf067262d..020e51afc7516ee92c8eff4ec36b46fa48298447 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2006, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2006, 2008, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -35,7 +35,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 
-#define        DNSINFO_VERSION         20091104
+#define        DNSINFO_VERSION         20111104
 
 #define DEFAULT_SEARCH_ORDER    200000   /* search order for the "default" resolver domain name */
 
@@ -72,12 +72,13 @@ typedef struct {
        DNS_VAR(uint32_t,               search_order);  /* search_order */
        DNS_VAR(uint32_t,               if_index);
        DNS_VAR(uint32_t,               flags);
-       DNS_VAR(uint32_t,               reserved[6]);
+       DNS_VAR(uint32_t,               reach_flags);   /* SCNetworkReachabilityFlags */
+       DNS_VAR(uint32_t,               reserved[5]);
 } dns_resolver_t;
 #pragma pack()
 
 
-#define DNS_RESOLVER_FLAGS_SCOPED      1
+#define DNS_RESOLVER_FLAGS_SCOPED      1               /* configuration is for scoped questions */
 
 
 #pragma pack(4)
@@ -105,6 +106,10 @@ dns_configuration_copy             ()                              __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0);
 void
 dns_configuration_free         (dns_config_t   *config)        __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0);
 
+void
+_dns_configuration_ack         (dns_config_t   *config,
+                                const char     *bundle_id)     __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0);
+
 __END_DECLS
 
 #endif /* __DNSINFO_H__ */
index 1a2ea6f0be7f6fb72c89ec6210cc40ba6ac38709..26b1e9de3f17a3eed069fc0532f12c796c4d18e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2006, 2008-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004, 2006, 2008-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include "dnsinfo.h"
 #include "dnsinfo_private.h"
 #include "shared_dns_info.h"
+#include "network_information_priv.h"
 
 
 static pthread_once_t  _dns_initialized        = PTHREAD_ONCE_INIT;
 static pthread_mutex_t _dns_lock               = PTHREAD_MUTEX_INITIALIZER;
 static mach_port_t     _dns_server             = MACH_PORT_NULL;
 
+enum {
+       get_dns_info    = 1,
+       get_nwi_state   = 2,
+};
+
+typedef uint32_t getflags;
 
 static void
 __dns_fork_handler()
@@ -83,14 +90,10 @@ add_list(void **padding, uint32_t *n_padding, int32_t count, int32_t size, void
 #define        DNS_CONFIG_BUF_MAX      1024*1024
 
 
-static _dns_config_buf_t *
-copy_dns_info()
-{
-       uint8_t                 *buf    = NULL;
-       dnsDataOut_t            dataRef = NULL;
-       mach_msg_type_number_t  dataLen = 0;
-       mach_port_t             server;
-       kern_return_t           status;
+static kern_return_t
+_dns_server_copy(void* dataRef, mach_msg_type_number_t* dataLen, getflags flags){
+       mach_port_t     server;
+       kern_return_t   status  = KERN_FAILURE;
 
        // initialize runtime
        pthread_once(&_dns_initialized, __dns_initialize);
@@ -99,7 +102,11 @@ copy_dns_info()
        server = _dns_server;
        while (TRUE) {
                if (server != MACH_PORT_NULL) {
-                       status = shared_dns_infoGet(server, &dataRef, &dataLen);
+                       if (flags == get_dns_info) {
+                               status = shared_dns_infoGet(server, dataRef, dataLen);
+                       } else {
+                               status = shared_nwi_stateGet(server, dataRef, dataLen);
+                       }
                        if (status == KERN_SUCCESS) {
                                break;
                        }
@@ -135,10 +142,62 @@ copy_dns_info()
                }
        }
 
+       return status;
+}
+
+
+__private_extern__
+nwi_state*
+_nwi_state_copy() {
+       dnsDataOut_t            dataRef         = NULL;
+       mach_msg_type_number_t  dataLen         = 0;
+       kern_return_t           status;
+       nwi_state*              state           = NULL;
+
+       status = _dns_server_copy(&dataRef, &dataLen, get_nwi_state);
+       if (status != KERN_SUCCESS) {
+               return NULL;
+       }
+
+       if (dataRef != NULL) {
+               state = malloc(dataLen);
+               if (state == NULL) {
+                       vm_deallocate(mach_task_self(), (vm_address_t)dataRef,
+                                     dataLen);
+                       return NULL;
+               }
+               memcpy((void*) state, (void*) dataRef, dataLen);
+               state->ref = 0;
+               status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
+               if (status != KERN_SUCCESS) {
+                       mach_error("vm_deallocate():", status);
+                       free(state);
+                       return NULL;
+               }
+       }
+
+       return state;
+}
+
+
+static _dns_config_buf_t *
+copy_dns_info()
+{
+       uint8_t                 *buf    = NULL;
+       dnsDataOut_t            dataRef = NULL;
+       mach_msg_type_number_t  dataLen = 0;
+       kern_return_t           status;
+
+       status = _dns_server_copy(&dataRef, &dataLen, get_dns_info);
+       if (status != KERN_SUCCESS) {
+               return NULL;
+       }
+
        if (dataRef != NULL) {
                if ((dataLen >= sizeof(_dns_config_buf_t)) && (dataLen <= DNS_CONFIG_BUF_MAX)) {
-                       _dns_config_buf_t       *config         = (_dns_config_buf_t *)dataRef;
-                       uint32_t                n_padding       = ntohl(config->n_padding);
+                       /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
+                       _dns_config_buf_t       *config         = (_dns_config_buf_t *)(void *)dataRef;
+                       uint32_t                n_padding       = ntohl(config->n_padding);
 
                        if (n_padding <= (DNS_CONFIG_BUF_MAX - dataLen)) {
                                uint32_t        len;
@@ -158,7 +217,8 @@ copy_dns_info()
                }
        }
 
-       return (_dns_config_buf_t *)buf;
+       /* ALIGN: buf malloc'ed, should be aligned >8 bytes */
+       return (_dns_config_buf_t *)(void *)buf;
 }
 
 
@@ -237,10 +297,15 @@ expand_resolver(_dns_resolver_buf_t *buf, uint32_t n_buf, void **padding, uint32
 
        resolver->flags = ntohl(resolver->flags);
 
+       // initialize SCNetworkReachability flags
+
+       resolver->reach_flags = ntohl(resolver->reach_flags);
+
        // process resolver buffer "attribute" data
 
        n_attribute = n_buf - sizeof(_dns_resolver_buf_t);
-       attribute   = (dns_attribute_t *)&buf->attribute[0];
+       /* ALIGN: alignment not assumed, using accessors */
+       attribute = (dns_attribute_t *)(void *)&buf->attribute[0];
        if (n_attribute != ntohl(buf->n_attribute)) {
                goto error;
        }
@@ -262,7 +327,7 @@ expand_resolver(_dns_resolver_buf_t *buf, uint32_t n_buf, void **padding, uint32
                                break;
 
                        case RESOLVER_ATTRIBUTE_SORTADDR :
-                               resolver->sortaddr[n_sortaddr++] = (dns_sortaddr_t *)&attribute->attribute[0];
+                               resolver->sortaddr[n_sortaddr++] = (dns_sortaddr_t *)(void *)&attribute->attribute[0];
                                break;
 
                        case RESOLVER_ATTRIBUTE_OPTIONS :
@@ -330,7 +395,7 @@ expand_config(_dns_config_buf_t *buf)
        // process configuration buffer "attribute" data
 
        n_attribute = ntohl(buf->n_attribute);
-       attribute   = (dns_attribute_t *)&buf->attribute[0];
+       attribute   = (dns_attribute_t *)(void *)&buf->attribute[0];
 
        while (n_attribute >= sizeof(dns_attribute_t)) {
                uint32_t        attribute_length        = ntohl(attribute->length);
@@ -343,7 +408,7 @@ expand_config(_dns_config_buf_t *buf)
 
                                // expand resolver buffer
 
-                               resolver = expand_resolver((_dns_resolver_buf_t *)&attribute->attribute[0],
+                               resolver = expand_resolver((_dns_resolver_buf_t *)(void *)&attribute->attribute[0],
                                                           attribute_length - sizeof(dns_attribute_t),
                                                           &padding,
                                                           &n_padding);
@@ -431,6 +496,13 @@ dns_configuration_free(dns_config_t *config)
        return;
 }
 
+
+void
+_dns_configuration_ack(dns_config_t *config, const char *bundle_id)
+{
+       return;
+}
+
 #ifdef MAIN
 
 int
index 820797aae0a3bbb61bdb60dd62b7e3f21448b0f9..db361d5931fe1bc8ea279770560d0a14a00e89bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004, 2006, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <strings.h>
 #include <mach/mach.h>
 #include <mach/mach_error.h>
+#include <CommonCrypto/CommonDigest.h>
 
 #include "dnsinfo_create.h"
 #include "dnsinfo_private.h"
 #include "shared_dns_info.h"
+#include "network_information_priv.h"
 
 
 #define ROUNDUP(a, size) \
@@ -92,7 +94,8 @@ config_add_attribute(dns_create_config_t      *_config,
 
        // add attribute [header]
 
-       header = (dns_attribute_t *)&config->attribute[oldLen];
+       /* ALIGN: _dns_config_buf_t is int aligned */
+       header = (dns_attribute_t *)(void *)&config->attribute[oldLen];
        header->type   = htonl(attribute_type);
        header->length = htonl(newLen);
 
@@ -151,6 +154,61 @@ _dns_configuration_add_resolver(dns_create_config_t     *_config,
        return;
 }
 
+_Bool
+_nwi_state_store(nwi_state* state)
+{
+       mach_port_t             server;
+       kern_return_t           status;
+       dnsDataOut_t            dataRef = (dnsDataOut_t) state;
+       mach_msg_type_number_t  dataLen = state->size;
+
+       server = _dns_configuration_server_port();
+       if (server == MACH_PORT_NULL) {
+               return FALSE;
+       }
+
+       status = shared_nwi_stateSet(server, dataRef, dataLen);
+
+       (void) mach_port_deallocate(mach_task_self(), server);
+
+       if (status != KERN_SUCCESS) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+void
+_dns_configuration_signature(dns_create_config_t       *_config,
+                            unsigned char              *signature,
+                            size_t                     signature_len)
+{
+       bzero(signature, signature_len);
+
+       if (_config != NULL) {
+               _dns_config_buf_t       *config = (_dns_config_buf_t *)*_config;
+
+               if (config != NULL) {
+                       CC_SHA1_CTX     ctx;
+                       unsigned char   *sha1;
+                       unsigned char   sha1_buf[CC_SHA1_DIGEST_LENGTH];
+
+                       sha1 = (signature_len >= CC_SHA1_DIGEST_LENGTH) ? signature : sha1_buf;
+                       CC_SHA1_Init(&ctx);
+                       CC_SHA1_Update(&ctx,
+                                      config,
+                                      sizeof(_dns_config_buf_t) + ntohl(config->n_attribute));
+                       CC_SHA1_Final(sha1, &ctx);
+                       if (sha1 != signature) {
+                               bcopy(sha1, signature, signature_len);
+                       }
+               }
+       }
+
+       return;
+}
+
 
 _Bool
 _dns_configuration_store(dns_create_config_t *_config)
@@ -238,7 +296,8 @@ _dns_resolver_add_attribute(dns_create_resolver_t   *_resolver,
 
        // add attribute [header]
 
-       header = (dns_attribute_t *)&resolver->attribute[oldLen];
+       /* ALIGN: _dns_config_buf_t is int aligned */
+       header = (dns_attribute_t *)(void *)&resolver->attribute[oldLen];
        header->type   = htonl(attribute_type);
        header->length = htonl(newLen);
 
@@ -276,6 +335,17 @@ _dns_resolver_add_search(dns_create_resolver_t *_resolver, const char *search)
 }
 
 
+void
+_dns_resolver_add_sortaddr(dns_create_resolver_t *_resolver, dns_sortaddr_t *sortaddr)
+{
+       _dns_resolver_buf_t     *resolver       = (_dns_resolver_buf_t *)*_resolver;
+
+       resolver->resolver.n_sortaddr = htonl(ntohl(resolver->resolver.n_sortaddr) + 1);
+       _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SORTADDR, sizeof(dns_sortaddr_t), (void *)sortaddr);
+       return;
+}
+
+
 void
 _dns_resolver_set_domain(dns_create_resolver_t *_resolver, const char *domain)
 {
@@ -333,12 +403,11 @@ _dns_resolver_set_port(dns_create_resolver_t *_resolver, uint16_t port)
 
 
 void
-_dns_resolver_add_sortaddr(dns_create_resolver_t *_resolver, dns_sortaddr_t *sortaddr)
+_dns_resolver_set_reach_flags(dns_create_resolver_t *_resolver, uint32_t reach_flags)
 {
        _dns_resolver_buf_t     *resolver       = (_dns_resolver_buf_t *)*_resolver;
 
-       resolver->resolver.n_sortaddr = htonl(ntohl(resolver->resolver.n_sortaddr) + 1);
-       _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SORTADDR, sizeof(dns_sortaddr_t), (void *)sortaddr);
+       resolver->resolver.reach_flags = htonl(reach_flags);
        return;
 }
 
index 5ad526d737c2cde9926eb58098c5fb38f1f56a9f..89c71b53911b2dd1543ad6e722331a5589f73ecd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2006, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2006, 2008, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -66,6 +66,12 @@ void
 _dns_configuration_add_resolver (dns_create_config_t   *_config,
                                 dns_create_resolver_t  _resolver)              /*__OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0)*/;
 
+__private_extern__
+void
+_dns_configuration_signature   (dns_create_config_t    *_config,
+                                unsigned char          *signature,
+                                size_t                 signature_len)          /*__OSX_AVAILABLE_STARTING(__MAC_10_7+,__IPHONE_5_0)*/; // signature_len >= CC_SHA1_DIGEST_LENGTH
+
 __private_extern__
 _Bool
 _dns_configuration_store       (dns_create_config_t    *_config)               /*__OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0)*/;
@@ -126,6 +132,11 @@ void
 _dns_resolver_set_port         (dns_create_resolver_t  *_resolver,
                                 uint16_t               port)                   /*__OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0)*/;  // host byte order
 
+__private_extern__
+void
+_dns_resolver_set_reach_flags  (dns_create_resolver_t  *_resolver,
+                                uint32_t               reach_flags)            /*__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0)*/;
+
 __private_extern__
 void
 _dns_resolver_set_timeout      (dns_create_resolver_t  *_resolver,
index 664fcb4de0711125d63f1fd254ddafb3dd3f6ce6..e052d2eb543f1ffb0a4d9d13271965864fcef395 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -143,10 +143,12 @@ _dnsinfo_parse_nameserver(char *token)
 
                switch (sa->sa_family) {
                        case AF_INET :
-                               ((struct sockaddr_in *)sa)->sin_port = port;
+                               /* ALIGN: cast ok, sockaddr was malloc'd */
+                               ((struct sockaddr_in *)(void *)sa)->sin_port = port;
                                break;
                        case AF_INET6 :
-                               ((struct sockaddr_in6 *)sa)->sin6_port = port;
+                               /* ALIGN: cast ok, sockaddr was malloc'd */
+                               ((struct sockaddr_in6 *)(void *)sa)->sin6_port = port;
                                break;
                }
        }
@@ -182,7 +184,8 @@ _dnsinfo_parse_sortaddr(char *token)
                // if not AF_INET
                goto done;
        } else {
-               addr = ((struct sockaddr_in *)sa)->sin_addr;
+               /* ALIGN: cast ok, sockaddr was malloc'd */
+               addr = ((struct sockaddr_in *)(void *)sa)->sin_addr;
                free(sa);
                sa = NULL;
        }
@@ -196,7 +199,8 @@ _dnsinfo_parse_sortaddr(char *token)
                        // if mask not AF_INET
                        goto done;
                } else {
-                       mask = ((struct sockaddr_in *)sa)->sin_addr;
+                       /* ALIGN: cast ok, sockaddr was malloc'd */
+                       mask = ((struct sockaddr_in *)(void *)sa)->sin_addr;
                        free(sa);
                        sa = NULL;
                }
index 9613311029c85d55db705b49d23c4c460cd43c46..1d8bcace732da3a807088d317c497b82b95482da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2008, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include "dnsinfo_server.h"
 #include "dnsinfo_private.h"
+#include <network_information.h>
 
-static CFDataRef       shared_dns_info         = NULL;
+static CFDataRef       shared_dns_info         = NULL;
+static  CFDataRef      shared_nwi_state        = NULL;
 
 __private_extern__
 kern_return_t
@@ -54,7 +56,12 @@ _shared_dns_infoGet(mach_port_t server, dnsDataOut_t *dataRef, mach_msg_type_num
        *dataLen = 0;
 
        if (shared_dns_info != NULL) {
-               if (!_SCSerializeData(shared_dns_info, (void **)dataRef, (CFIndex *)dataLen)) {
+               CFIndex len;
+               Boolean ok;
+
+               ok = _SCSerializeData(shared_dns_info, (void **)dataRef, &len);
+               *dataLen = len;
+               if (!ok) {
                        return KERN_FAILURE;
                }
        }
@@ -63,19 +70,21 @@ _shared_dns_infoGet(mach_port_t server, dnsDataOut_t *dataRef, mach_msg_type_num
 }
 
 
-__private_extern__
+static
 kern_return_t
-_shared_dns_infoSet(mach_port_t                        server,
-                   dnsData_t                   dataRef,
-                   mach_msg_type_number_t      dataLen,
-                   audit_token_t               audit_token)
+_shared_infoSet_common(mach_port_t             server,
+                      dnsData_t                dataRef,
+                      mach_msg_type_number_t   dataLen,
+                      audit_token_t            audit_token,
+                      CFDataRef*               cache,
+                      const char*              notify_key)
 {
        uid_t           euid            = 0;
-       CFDataRef       new_dns_info    = NULL;
-       const char      *notify_key;
+       CFDataRef       new_info        = NULL;
+       CFDataRef       n_cache         = *cache;
 
        if ((dataRef != NULL) && (dataLen > 0)) {
-               if (!_SCUnserializeData(&new_dns_info, (void *)dataRef, dataLen)) {
+               if (!_SCUnserializeData(&new_info, (void *)dataRef, dataLen)) {
                        goto error;
                }
        }
@@ -93,17 +102,16 @@ _shared_dns_infoSet(mach_port_t                    server,
                goto error;
        }
 
-       if ((shared_dns_info != NULL) &&
-           (new_dns_info    != NULL) &&
-           CFEqual(shared_dns_info, new_dns_info)) {
-               CFRelease(new_dns_info);
+       if ((n_cache != NULL) &&
+           (new_info != NULL) &&
+           CFEqual(n_cache, new_info)) {
+               CFRelease(new_info);
                return KERN_SUCCESS;
        }
 
-       if (shared_dns_info != NULL) CFRelease(shared_dns_info);
-       shared_dns_info = new_dns_info;
+       if (n_cache != NULL) CFRelease(n_cache);
+       *cache = new_info;
 
-       notify_key = _dns_configuration_notify_key();
        if (notify_key != NULL) {
                uint32_t        status;
 
@@ -118,6 +126,62 @@ _shared_dns_infoSet(mach_port_t                    server,
 
     error :
 
-       if (new_dns_info != NULL)    CFRelease(new_dns_info);
+       if (new_info != NULL)    CFRelease(new_info);
        return KERN_FAILURE;
 }
+
+
+__private_extern__
+kern_return_t
+_shared_dns_infoSet(mach_port_t                        server,
+                   dnsData_t                   dataRef,
+                   mach_msg_type_number_t      dataLen,
+                   audit_token_t               audit_token)
+{
+       const char      *notify_key;
+
+       notify_key = _dns_configuration_notify_key();
+       return _shared_infoSet_common(server, dataRef, dataLen,
+                                     audit_token, &shared_dns_info,
+                                     notify_key);
+}
+
+
+__private_extern__
+kern_return_t
+_shared_nwi_stateGet(mach_port_t server, dnsDataOut_t *dataRef, mach_msg_type_number_t *dataLen)
+{
+       *dataRef = NULL;
+       *dataLen = 0;
+
+       if (shared_nwi_state != NULL) {
+               CFIndex len;
+               Boolean ok;
+
+               ok = _SCSerializeData(shared_nwi_state, (void **)dataRef, &len);
+               *dataLen = len;
+               if (!ok) {
+                       return KERN_FAILURE;
+               }
+       }
+
+       return KERN_SUCCESS;
+
+}
+
+
+__private_extern__
+kern_return_t
+_shared_nwi_stateSet(mach_port_t               server,
+                    dnsData_t                  dataRef,
+                    mach_msg_type_number_t     dataLen,
+                    audit_token_t              audit_token)
+{
+       const char      *notify_key;
+
+       notify_key = nwi_state_get_notify_key();
+
+       return _shared_infoSet_common(server, dataRef, dataLen,
+                                     audit_token, &shared_nwi_state,
+                                     notify_key);
+}
index 44350a8bccb8924e45396a157b94118554a0f836..7483a3e41657934a71fd59b4cd2e8f275e0dce18 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005, 2009 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004, 2005, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -43,6 +43,17 @@ kern_return_t        _shared_dns_infoSet     (mach_port_t            server,
                                         mach_msg_type_number_t dataLen,
                                         audit_token_t          audit_token);
 
+__private_extern__
+kern_return_t  _shared_nwi_stateGet    (mach_port_t            server,
+                                        dnsDataOut_t           *dataRef,
+                                        mach_msg_type_number_t *dataLen);
+
+__private_extern__
+kern_return_t  _shared_nwi_stateSet    (mach_port_t            server,
+                                        dnsData_t              dataRef,
+                                        mach_msg_type_number_t dataLen,
+                                        audit_token_t          audit_token);
+
 __END_DECLS
 
 #endif /* !_S_DNSINFO_SERVER_H */
index bbb1e84d906bc85c165696659893982e3a87183c..4a24c43d111fce82c8146ebd02e97fe44c085b20 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005, 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004, 2005, 2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -61,4 +61,16 @@ routine shared_dns_infoSet   (       server          : mach_port_t;
                    ServerAuditToken    audit_token     : audit_token_t);
 #else  // LIBDNSINFO_A
        skip;           /* shared_dns_infoSet */
-#endif LIBDNSINFO_A
+#endif // LIBDNSINFO_A
+
+routine shared_nwi_stateGet     (      server          : mach_port_t;
+                               out     data            : dnsDataOut, dealloc);
+
+#ifndef LIBDNSINFO_A
+routine shared_nwi_stateSet    (       server          : mach_port_t;
+                               data                    : dnsData;
+                   ServerAuditToken    audit_token     : audit_token_t);
+#else   // LIBDNSINFO_A
+       skip;           /* shared_nwi_stateSet */
+#endif  // LIBDNSINFO_A
+
index adc3d6a3805d6194b9f41ed1207364fba9d43080..818391c119f8fe8aa7f837dfce5f8b9740ee8233 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/sh
-# Copyright (c) 2004-2011 Apple Inc.
+# Copyright (c) 2004-2012 Apple Inc.
 #
 # get-mobility-info
 #
@@ -46,6 +46,10 @@ fi
 
 cd "${WORKDIR}"
 
+echo ""
+echo "Please wait, collecting information and statistics"
+echo ""
+
 #
 # processes
 #
@@ -102,6 +106,29 @@ fi
 ioreg -i -l -w 0                                       >  ioreg                2>&1
 ioreg -i -l -p IODeviceTree -w 0                       >> ioreg                2>&1
 
+#
+# Power Management info
+#
+echo "#"                                               >  pmset
+echo "# pmset -g"                                      >> pmset
+echo "#"                                               >> pmset
+pmset -g                                               >> pmset                2>&1
+
+echo "#"                                               >> pmset
+echo "# pmset -g ps"                                   >> pmset
+echo "#"                                               >> pmset
+pmset -g ps                                            >> pmset                2>&1
+
+echo "#"                                               >> pmset
+echo "# pmset -g assertions"                           >> pmset
+echo "#"                                               >> pmset
+pmset -g assertions                                    >> pmset                2>&1
+
+echo "#"                                               >> pmset
+echo "# pmset -g log"                                  >> pmset
+echo "#"                                               >> pmset
+pmset -g log  | tail -n 25000                          >> pmset                2>&1
+
 #
 # Host name
 #
@@ -129,7 +156,12 @@ fi
 #
 # Proxy configuration
 #
-scutil --proxy                                         > proxy-configuration   2>&1
+scutil -d -v --proxy                                   > proxy-configuration   2>&1
+
+#
+# Network information
+#
+scutil --nwi                                           > network-information   2>&1
 
 #
 # System / network preferences
@@ -139,7 +171,6 @@ for f in                                                                            \
        /Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist        \
        /Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist    \
        /Library/Preferences/SystemConfiguration/com.apple.nat.plist                    \
-       /Library/Preferences/SystemConfiguration/com.apple.network.identification.plist \
        /Library/Preferences/SystemConfiguration/com.apple.smb.server.plist             \
        /Library/Preferences/SystemConfiguration/com.apple.wifi.plist                   \
        /Library/Preferences/SystemConfiguration/preferences.plist                      \
@@ -159,20 +190,16 @@ done
 #
 if   [ -e /etc/bootpd.plist ]; then
        cat /etc/bootpd.plist                                                   > bootpd.plist                  2>&1
-       cat /etc/com.apple.named.proxy.conf                                     > com.apple.named.proxy.conf    2>&1
+       cat /etc/com.apple.named.proxy.conf                                     > com.apple.named.proxy.conf    2>/dev/null
 elif [ -e /Library/Preferences/SystemConfiguration/bootpd.plist ]; then
        cat /Library/Preferences/SystemConfiguration/bootpd.plist               > bootpd.plist                  2>&1
-       cat /Library/Preferences/SystemConfiguration/com.apple.named.proxy.conf > com.apple.named.proxy.conf    2>&1
+       cat /Library/Preferences/SystemConfiguration/com.apple.named.proxy.conf > com.apple.named.proxy.conf    2>/dev/null
 fi
 
 #
 # configd's cache
 #
-${PRIV} scutil -p <<_END_OF_INPUT
-open
-snapshot
-quit
-_END_OF_INPUT
+${PRIV} scutil -p --snapshot
 if [ -f /var/tmp/configd-store.plist ]; then
        cat /var/tmp/configd-store.plist                > configd-store.plist   2>&1
 fi
@@ -185,26 +212,14 @@ fi
 if [ -f /var/tmp/configd-state ]; then
        cat /var/tmp/configd-state                      > configd-state         2>&1
 fi
-
-#
-# check configd's executable
-#
-if [ -x /usr/bin/codesign ]; then
-       echo  "#"                                                                       >> configd-state
-       echo  "# codesign --verbose --display --entitlements - /usr/libexec/configd"    >> configd-state
-       echo  "#"                                                                       >> configd-state
-       /usr/bin/codesign --verbose --display --entitlements - /usr/libexec/configd     >> configd-state 2>&1
-
-       echo  "#"                                                                       >> configd-state
-       echo  "# codesign --verbose --verify /usr/libexec/configd"                      >> configd-state
-       echo  "#"                                                                       >> configd-state
-       /usr/bin/codesign --verbose --verify /usr/libexec/configd                       >> configd-state 2>&1
+if [ -f /var/tmp/configd-reachability ]; then
+       cat /var/tmp/configd-reachability               > configd-reachability          2>&1
 fi
 
 #
 # network reachability
 #
-scutil -d -v -r www.apple.com                          > reachability-info     2>&1
+scutil -d -v -r www.apple.com "" no-server             > reachability-info     2>&1
 if [ -x /usr/bin/dig -a -f /etc/resolv.conf ]; then
        /usr/bin/dig -t any -c any www.apple.com        > dig-results           2>/dev/null
 fi
@@ -215,10 +230,11 @@ fi
 mount                                                  > mounted-filesystems   2>&1
 
 #
-# mDNSResponder info
+# mDNSResponder, networkd info
 #
 if [ -x /usr/bin/killall ]; then
        ${PRIV} killall -INFO mDNSResponder
+       ${PRIV} killall -INFO networkd
 
        # and wait a short amount of time for mDNSResponder
        # to actually log the requested information
@@ -344,6 +360,11 @@ echo "# netstat -i -n -d"                          >> network-statistics
 echo "#"                                               >> network-statistics
 netstat -i -n -d                                       >> network-statistics   2>&1
 
+echo "#"                                               >> network-statistics
+echo "# netstat -g -n -s"                              >> network-statistics
+echo "#"                                               >> network-statistics
+netstat -g -n -s                                       >> network-statistics   2>&1
+
 if [ -x /usr/sbin/ndp ]; then
        echo "#"                                        >> network-statistics
        echo "# ndp -n -a"                              >> network-statistics
@@ -359,6 +380,14 @@ if [ -x /usr/sbin/ndp ]; then
        echo "# ndp -n -r"                              >> network-statistics
        echo "#"                                        >> network-statistics
        ndp -n -r                                       >> network-statistics   2>&1
+
+       for if in `ifconfig -l`
+       do
+               echo "#"                                >> network-statistics
+               echo "# ndp -i ${if}"                   >> network-statistics
+               echo "#"                                >> network-statistics
+               ndp -i ${if}                            >> network-statistics   2>&1
+       done
 fi
 
 if [ -x /sbin/ipfw ]; then
@@ -368,6 +397,13 @@ if [ -x /sbin/ipfw ]; then
        ${PRIV} ipfw -at show                           >> network-statistics   2>&1
 fi
 
+if [ -x /sbin/ip6fw ]; then
+       echo "#"                                        >> network-statistics
+       echo "# ip6fw -at show"                 >> network-statistics
+       echo "#"                                        >> network-statistics
+       ${PRIV} ip6fw -at show                          >> network-statistics   2>&1
+fi
+
 if [ -x /sbin/pfctl ]; then
        echo "#"                                        >  pf
        echo "# pfctl -s all"                           >> pf
@@ -378,7 +414,7 @@ if [ -x /sbin/pfctl ]; then
        echo "# pfctl -s References"                    >> pf
        echo "#"                                        >> pf
        ${PRIV} pfctl -s References                     >> pf                   2>&1
-       for ANCHOR in `pfctl -s Anchors 2>/dev/null`
+       for ANCHOR in `${PRIV} pfctl -s Anchors -v 2>/dev/null`
        do
                echo "=============================="   >> pf
                echo "#"                                >> pf
@@ -427,10 +463,9 @@ echo "#"                                           >  ipsec
 echo "# setkey -D"                                     >> ipsec
 echo "#"                                               >> ipsec
 ${PRIV} setkey -D                                      \
-| perl -nle '
+| perl -M'Digest::MD5 qw(md5_hex)' -l -n -e '
        if (/^(\s+[AE]:\s+\S+\s+)"?(.*)"?\s*$/) {
-               chop($sha1=`echo "$2" | openssl sha1`);
-               printf "%s[SHA-1:%s]\n", $1, $sha1;
+               printf "%s[MD5:%s]%s\n", $1, md5_hex($2 . "\n"), $3;
        } else {
                printf "%s\n", $_;
        }
@@ -453,10 +488,9 @@ do
        echo "# ${CF}"                                  >> ipsec
        echo "#"                                        >> ipsec
        ${PRIV} cat ${CF}                               \
-       | perl -nle '
+       | perl -M'Digest::MD5 qw(md5_hex)' -l -n -e '
                if (/^(\s+shared_secret\s+use\s+)"?([^\s;"]+)"?(.*)/) {
-                       chop($sha1=`echo "$2" | openssl sha1`);
-                       printf "%s[SHA-1:%s]%s\n", $1, $sha1, $3;
+                       printf "%s[MD5:%s]%s\n", $1, md5_hex($2 . "\n"), $3;
                } else {
                        printf "%s\n", $_;
                }
@@ -514,23 +548,23 @@ BTMM_CHECKMACDOTCOM()
 BTMM_DIG()
 {
        rm -f .digsync
-       
+
        nc -6 -l "${BTMMPORT}" < .btmmfifo                      \
        | openssl s_client      -connect "${HOSTPORT}" -quiet   > .btmmfifo     2>.digsync &
-       
+
        N_RETRY=0
        while [ $N_RETRY -lt 50 -a ! -s .digsync ]
        do
                N_RETRY=$((N_RETRY + 1))
                sleep 0.1
        done
-       
+
        dig @::1        -p "${BTMMPORT}"                \
                        -y "${TSIG}"                    \
                        +short                          \
                        +tcp                            \
                        "${1}" "${2}"                   2>/dev/null
-       
+
        wait %1
 }
 
@@ -546,7 +580,7 @@ BTMM_UNIQUEIDFROMZONE()
        fi
 }
 
-# get hostname, port, TSIG name and TSIG data from keychain 
+# get hostname, port, TSIG name and TSIG data from keychain
 # params: UNIQUEID
 BTMM_GETINFO()
 {
@@ -556,7 +590,7 @@ BTMM_GETINFO()
        ${PRIV} security find-generic-password          \
                -s "${1}"                               \
                -g /Library/Keychains/System.keychain   \
-               2>&1                                    \
+               2>&1 > /dev/null                        \
        | sed -n 's/^password: \"\(.*\)\"$/\1/p'
 }
 
@@ -577,22 +611,24 @@ BTMM_RELAYINFO()
        if [ $? -eq 0 ]; then
                return
        fi
-       
+
        SECRET=`BTMM_GETINFO "btmmrelay:${1}"`
-       
+
        if [ -z "${SECRET}" ]; then
                echo "  No Relay keychain item."                >> btmm
                return
        fi
-       
+
        if [ `echo "${SECRET}" | wc -l` -ne 1 ]; then
                echo "  More than one Relay keychain item."     >> btmm
                return
        fi
-       
+
        URLISH=`BTMM_URLISH "${DOMAIN}"`
        ACCOUNT=`cat .btmminfo | sed -n 's/.*\"acct\"<blob>=\"\(.*\)\"/\1/p'`
-       KEYHASH="[SHA-1:`echo ${SECRET} | openssl sha1`]"
+       KEYHASH="`perl -M'Digest::SHA1 qw(sha1_hex)' -l -e '
+                       printf "[SHA1:%s]\n", sha1_hex($ARGV[0] . "\n");
+       ' ${SECRET}`"
        echo "  RHP: ${URLISH}"                                 >> btmm
        echo "  RAC: ${ACCOUNT}"                                >> btmm
        echo "  RKY: ${KEYHASH}"                                >> btmm
@@ -601,10 +637,10 @@ BTMM_RELAYINFO()
 BTMM_REPORTZONE()
 {
        DOMAIN="${1}"
-       
+
        echo                                                    >> btmm
        echo "${DOMAIN}"                                        >> btmm
-       
+
        DNSID=`BTMM_UNIQUEIDFROMZONE "${DOMAIN}"`
        SECRET=`BTMM_GETINFO "${DNSID}"`
 
@@ -612,25 +648,37 @@ BTMM_REPORTZONE()
                echo "  No DNS keychain item."                  >> btmm
                return
        fi
-       
+
        if [ `echo "${SECRET}" | wc -l` -ne 1 ]; then
                echo "  More than one DNS keychain item."       >> btmm
                return
        fi
-       
+
        URLISH=`BTMM_URLISH "${DOMAIN}"`
        HOSTPORT=`echo "${URLISH}" | cut -d@ -f2`
        ACCOUNT=`cat .btmminfo | sed -n 's/.*\"acct\"<blob>=\"\(.*\)\"/\1/p'`
        TSIG="${ACCOUNT}:${SECRET}"
 
-       KEYHASH="[SHA-1:`echo ${SECRET} | openssl sha1`]"
+       KEYHASH="`perl -M'Digest::SHA1 qw(sha1_hex)' -l -e '
+                       printf "[SHA1:%s]\n", sha1_hex($ARGV[0] . "\n");
+               ' ${SECRET}`"
        echo ""                                                 >> btmm
        echo "  DHP: ${URLISH}"                                 >> btmm
        echo "  DAC: ${ACCOUNT}"                                >> btmm
        echo "  DKY: ${KEYHASH}"                                >> btmm
-       
+
        BTMM_RELAYINFO "${DOMAIN}"
 
+       REACHHOST=`echo "${HOSTPORT}" | cut -d: -f1`
+       STATUSES=`scutil -r "${REACHHOST}"`
+       for REACHSTATUS in `echo ${STATUSES} | tr -d ' ' | tr ',' ' '`; do
+               if [ "$REACHSTATUS" == "NotReachable" ] \
+                       || [ "$REACHSTATUS" == "ConnectionRequired" ]; then
+                       echo "  Skipping DNS queries, no connectivity"  >> btmm
+                       return
+               fi
+       done
+
        for TYPE in                     \
                _afpovertcp._tcp        \
                _airport._tcp           \
@@ -744,12 +792,14 @@ for daemon in                             \
                pppd                    \
                racoon                  \
                socketfilterfw          \
+               InternetSharing         \
                SCHelper                \
                SCMonitor               \
 
 do
        /bin/ls -1      /Library/Logs/DiagnosticReports/${daemon}_*.crash       \
                        /Library/Logs/CrashReporter/${daemon}_*.crash           \
+                       /Library/Logs/CrashReporter/${daemon}_*.plist           \
                        2>/dev/null                                             \
        | while read log
        do
@@ -760,6 +810,21 @@ do
        done
 done
 
+#
+# system profiler
+#
+if [ -x /usr/sbin/system_profiler ]; then
+       system_profiler -xml    SPEthernetDataType      \
+                               SPFibreChannelDataType  \
+                               SPFireWireDataType      \
+                               SPFirewallDataType      \
+                               SPModemDataType         \
+                               SPNetworkDataType       \
+                               SPThunderboltDataType   \
+                               SPWWANDataType          \
+                               SPAirPortDataType       > system_profiler.spx   2>&1
+fi
+
 #
 # system usage statistics
 #
@@ -781,9 +846,6 @@ zprint                                                      >> system-statistics    2>&1
 echo "#"                                               >> system-statistics
 echo "# top -l5 -s2"                                   >> system-statistics
 echo "#"                                               >> system-statistics
-echo ""
-echo "Please wait, collecting statistics"
-echo ""
 top -s 2 -l 5                                          >> system-statistics    2>&1
 
 #
diff --git a/nwi/network_information.c b/nwi/network_information.c
new file mode 100644 (file)
index 0000000..18b4c6b
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <pthread.h>
+#include <notify.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include "network_information.h"
+#include "network_information_priv.h"
+
+static nwi_state_t     G_nwi_state             = NULL;
+static pthread_mutex_t nwi_store_lock          = PTHREAD_MUTEX_INITIALIZER;
+static boolean_t       nwi_store_token_valid   = FALSE;
+
+static pthread_once_t  initialized             = PTHREAD_ONCE_INIT;
+static int             nwi_store_token;
+
+
+/* Private */
+static
+void
+_nwi_state_initialize(void)
+{
+       const char      *nwi_key        = nwi_state_get_notify_key();
+       uint32_t        status          = notify_register_check(nwi_key,
+                                                               &nwi_store_token);
+
+       if (status != NOTIFY_STATUS_OK) {
+               fprintf(stderr, "nwi_state: registration failed (%u)\n", status);
+       }
+       else {
+               nwi_store_token_valid = TRUE;
+       }
+}
+
+static
+void
+nwi_set_alias(nwi_state* state, nwi_ifstate* ifstate)
+{
+       nwi_ifstate*      ifstate_alias;
+       int af = ifstate->af;
+       int af_alias;
+
+       af_alias = (af == AF_INET)?AF_INET6:AF_INET;
+
+       ifstate_alias =
+               nwi_state_get_ifstate_with_name(state, af_alias,
+                                       ifstate->ifname);
+
+       if (ifstate_alias != NULL) {
+               ifstate_alias->af_alias = ifstate;
+       }
+       ifstate->af_alias = ifstate_alias;
+       return;
+}
+
+static
+void
+_nwi_state_reset_alias(nwi_state_t state) {
+       int i;
+
+       for (i = 0; i < state->ipv4_count; i++) {
+               state->nwi_ifstates[i].af_alias = NULL;
+       }
+
+       for (i = state->ipv6_start;
+            i < state->ipv6_start + state->ipv6_count; i++) {
+               nwi_set_alias(state, &state->nwi_ifstates[i]);
+       }
+}
+
+/* Public APIs' */
+/*
+ * Function: nwi_state_get_notify_key
+ * Purpose:
+ *   Returns the BSD notify key to use to monitor when the state changes.
+ *
+ * Note:
+ *   The nwi_state_copy API uses this notify key to monitor when the state
+ *   changes, so each invocation of nwi_state_copy returns the current
+ *   information.
+ */
+const char *
+nwi_state_get_notify_key()
+{
+       return "com.apple.system.SystemConfiguration.nwi";
+}
+
+#define ATOMIC_INC(p)          __sync_fetch_and_add((p), 1)            // return (n++);
+#define ATOMIC_DEC(p)          __sync_sub_and_fetch((p), 1)            // return (--n);
+
+static void
+nwi_state_retain(nwi_state_t state)
+{
+       ATOMIC_INC(&state->ref);
+       return;
+}
+
+/*
+ * Function: nwi_state_release
+ * Purpose:
+ *   Release the memory associated with the network state.
+ */
+void
+nwi_state_release(nwi_state_t state)
+{
+       if (ATOMIC_DEC(&state->ref) == 0) {
+               free(state);
+       }
+       return;
+}
+
+/*
+ * Function: nwi_state_copy
+ * Purpose:
+ *   Returns the current network state information.
+ *   Release after use by calling nwi_state_release().
+ */
+nwi_state_t
+nwi_state_copy(void)
+{
+       nwi_state_t     nwi_state = NULL;
+       nwi_state_t     old_state = NULL;
+
+       pthread_once(&initialized, _nwi_state_initialize);
+       pthread_mutex_lock(&nwi_store_lock);
+
+       if (G_nwi_state != NULL) {
+               int             check = 0;
+               uint32_t        status;
+
+               if (nwi_store_token_valid == FALSE) {
+                       /* have to throw cached copy away every time */
+                       check = 1;
+               }
+               else {
+                       status = notify_check(nwi_store_token, &check);
+                       if (status != NOTIFY_STATUS_OK) {
+                               fprintf(stderr, "nwi notify_check: failed with %u\n",
+                                       status);
+                               /* assume that it changed, throw cached copy away */
+                               check = 1;
+                       }
+               }
+               if (check != 0) {
+                       /* new need snapshot */
+                       old_state = G_nwi_state;
+                       G_nwi_state = NULL;
+               }
+       }
+       /* Let's populate the cache if it's empty */
+       if (G_nwi_state == NULL) {
+               G_nwi_state = _nwi_state_copy();
+               if (G_nwi_state != NULL) {
+                       /* one reference for G_nwi_state */
+                       nwi_state_retain(G_nwi_state);
+                       _nwi_state_reset_alias(G_nwi_state);
+               }
+       }
+       if (G_nwi_state != NULL) {
+               /* another reference for this caller */
+               nwi_state_retain(G_nwi_state);
+       }
+       nwi_state = G_nwi_state;
+       pthread_mutex_unlock(&nwi_store_lock);
+
+       if (old_state != NULL) {
+               /* get rid of G_nwi_state reference */
+               nwi_state_release(old_state);
+       }
+       return nwi_state;
+}
+
+/*
+ * Function: _nwi_state_ack
+ * Purpose:
+ *   Acknowledge receipt and any changes associated with the [new or
+ *   updated] network state.
+ */
+void
+_nwi_state_ack(nwi_state_t state, const char *bundle_id)
+{
+       return;
+}
+
+/*
+ * Function: nwi_state_get_generation
+ * Purpose:
+ *   Returns the generation (mach_time) of the nwi_state data.
+ *   Every time the data is updated due to changes
+ *   in the network, this value will change.
+ */
+uint64_t
+nwi_state_get_generation(nwi_state_t state)
+{
+       return (state->generation_count);
+}
+
+/*
+ * Function: nwi_ifstate_get_ifname
+ * Purpose:
+ *   Return the interface name of the specified ifstate.
+ */
+const char *
+nwi_ifstate_get_ifname(nwi_ifstate_t ifstate)
+{
+       return (ifstate != NULL?ifstate->ifname:NULL);
+
+}
+
+static uint64_t
+flags_from_af(int af)
+{
+    return ((af == AF_INET)
+           ? NWI_IFSTATE_FLAGS_HAS_IPV4
+           : NWI_IFSTATE_FLAGS_HAS_IPV6);
+}
+/*
+ * Function: nwi_ifstate_get_flags
+ * Purpose:
+ *   Return the flags for the given ifstate (see above for bit definitions).
+ */
+nwi_ifstate_flags
+nwi_ifstate_get_flags(nwi_ifstate_t ifstate)
+{
+       nwi_ifstate_t           alias = ifstate->af_alias;
+       nwi_ifstate_flags       flags = 0ULL;
+
+       flags |= flags_from_af(ifstate->af);
+       if ((ifstate->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0) {
+               flags |= NWI_IFSTATE_FLAGS_HAS_DNS;
+
+       }
+       if (alias != NULL) {
+               flags |= flags_from_af(alias->af);
+               if ((alias->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0) {
+                       flags |= NWI_IFSTATE_FLAGS_HAS_DNS;
+               }
+       }
+       return flags;
+}
+
+/*
+ * Function: nwi_state_get_first_ifstate
+ * Purpose:
+ *   Returns the first and highest priority interface that has connectivity
+ *   for the specified address family 'af'. 'af' is either AF_INET or AF_INET6.
+ *   The connectivity provided is for general networking.   To get information
+ *   about an interface that isn't available for general networking, use
+ *   nwi_state_get_ifstate().
+ *
+ *   Use nwi_ifstate_get_next() to get the next, lower priority interface
+ *   in the list.
+ *
+ *   Returns NULL if no connectivity for the specified address family is
+ *   available.
+ */
+nwi_ifstate_t
+nwi_state_get_first_ifstate(nwi_state_t state, int af)
+{
+       nwi_ifstate_t ifstate;
+
+       if (state == NULL) {
+               return NULL;
+       }
+
+       ifstate =
+               nwi_state_get_ifstate_with_index(state, af, 0);
+
+       if ((ifstate->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST)
+           != 0) {
+               ifstate =  NULL;
+       }
+
+       return ifstate;
+
+}
+
+/*
+ * Function: nwi_state_get_ifstate
+ * Purpose:
+ *   Return information for the specified interface 'ifname'.
+ *
+ *   This API directly returns the ifstate for the specified interface.
+ *   This is the only way to access information about an interface that isn't
+ *   available for general networking.
+ *
+ *   Returns NULL if no information is available for that interface.
+ */
+nwi_ifstate_t
+nwi_state_get_ifstate(nwi_state_t state, const char * ifname)
+{
+       nwi_ifstate_t ifstate = nwi_state_get_ifstate_with_name(state, AF_INET, ifname);
+       if (ifstate == NULL) {
+               ifstate = nwi_state_get_ifstate_with_name(state, AF_INET6, ifname);
+       }
+       return ifstate;
+
+}
+
+/*
+ * Function: nwi_ifstate_get_next
+ * Purpose:
+ *   Returns the next, lower priority nwi_ifstate_t after the specified
+ *   'ifstate' for the protocol family 'af'.
+ *
+ *   Returns NULL when the end of the list is reached.
+ */
+nwi_ifstate_t
+nwi_ifstate_get_next(nwi_ifstate_t ifstate, int af)
+{
+       nwi_ifstate_t alias, next;
+
+       alias =
+               (af == ifstate->af)?ifstate:ifstate->af_alias;
+
+       if (alias == NULL) {
+               return NULL;
+       }
+
+       /* We don't return interfaces marked rank never */
+       if ((alias->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0) {
+               return NULL;
+       }
+
+       next = ++alias;
+
+       if ((next->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) == 0) {
+               return next;
+       }
+       return NULL;
+}
+
+/*
+ * Function: nwi_ifstate_compare_rank
+ * Purpose:
+ *   Compare the relative rank of two nwi_ifstate_t objects.
+ *
+ *   The "rank" indicates the importance of the underlying interface.
+ *
+ * Returns:
+ *   0         if ifstate1 and ifstate2 are ranked equally
+ *  -1 if ifstate1 is ranked ahead of ifstate2
+ *   1 if ifstate2 is ranked ahead of ifstate1
+ */
+int
+nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2)
+{
+       return RankCompare(ifstate1->rank, ifstate2->rank);
+}
diff --git a/nwi/network_information.h b/nwi/network_information.h
new file mode 100644 (file)
index 0000000..418b304
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef _NETWORK_INFORMATION_H_
+#define _NETWORK_INFORMATION_H_
+
+#include <stdint.h>
+
+typedef struct _nwi_state * nwi_state_t;
+typedef struct _nwi_ifstate * nwi_ifstate_t;
+
+/*
+ * Function: nwi_state_copy
+ * Purpose:
+ *   Returns the current network state information.
+ *   Release after use by calling nwi_state_release().
+ */
+nwi_state_t
+nwi_state_copy(void);
+
+/*
+ * Function: nwi_state_release
+ * Purpose:
+ *   Release the memory associated with the network state.
+ */
+void
+nwi_state_release(nwi_state_t state);
+
+/*
+ * Function: nwi_state_get_notify_key
+ * Purpose:
+ *   Returns the BSD notify key to use to monitor when the state changes.
+ *
+ * Note:
+ *   The nwi_state_copy API uses this notify key to monitor when the state
+ *   changes, so each invocation of nwi_state_copy returns the current
+ *   information.
+ */
+const char *
+nwi_state_get_notify_key(void);
+
+/*
+ * Function: nwi_state_get_first_ifstate
+ * Purpose:
+ *   Returns the first and highest priority interface that has connectivity
+ *   for the specified address family 'af'. 'af' is either AF_INET or AF_INET6.
+ *   The connectivity provided is for general networking.   To get information
+ *   about an interface that isn't available for general networking, use
+ *   nwi_state_get_ifstate().
+ *
+ *   Use nwi_ifstate_get_next() to get the next, lower priority interface
+ *   in the list.
+ *
+ *   Returns NULL if no connectivity for the specified address family is
+ *   available.
+ */
+nwi_ifstate_t
+nwi_state_get_first_ifstate(nwi_state_t state, int af);
+
+/*
+ * Function: nwi_state_get_generation
+ * Purpose:
+ *   Returns the generation (mach_time) of the nwi_state data.
+ *   Every time the data is updated due to changes
+ *   in the network, this value will change.
+ */
+uint64_t
+nwi_state_get_generation(nwi_state_t state);
+
+/*
+ * Function: nwi_state_get_ifstate
+ * Purpose:
+ *   Return information for the specified interface 'ifname'.
+ *
+ *   This API directly returns the ifstate for the specified interface.
+ *   This is the only way to access information about an interface that isn't
+ *   available for general networking.
+ *
+ *   Returns NULL if no information is available for that interface.
+ */
+nwi_ifstate_t
+nwi_state_get_ifstate(nwi_state_t state, const char * ifname);
+
+/*
+ * Function: nwi_ifstate_get_ifname
+ * Purpose:
+ *   Return the interface name of the specified ifstate.
+ */
+const char *
+nwi_ifstate_get_ifname(nwi_ifstate_t ifstate);
+
+/*
+ * Type: nwi_ifstate_flags
+ * Purpose:
+ *   Provide information about the interface, including its IPv4 and IPv6
+ *   connectivity, and whether DNS is configured or not.
+ */
+#define NWI_IFSTATE_FLAGS_HAS_IPV4     0x1     /* has IPv4 connectivity */
+#define NWI_IFSTATE_FLAGS_HAS_IPV6     0x2     /* has IPv6 connectivity */
+#define NWI_IFSTATE_FLAGS_HAS_DNS      0x4     /* has DNS configured */
+
+typedef uint64_t nwi_ifstate_flags;
+/*
+ * Function: nwi_ifstate_get_flags
+ * Purpose:
+ *   Return the flags for the given ifstate (see above for bit definitions).
+ */
+nwi_ifstate_flags
+nwi_ifstate_get_flags(nwi_ifstate_t ifstate);
+
+/*
+ * Function: nwi_ifstate_get_next
+ * Purpose:
+ *   Returns the next, lower priority nwi_ifstate_t after the specified
+ *   'ifstate' for the protocol family 'af'.
+ *
+ *   Returns NULL when the end of the list is reached.
+ */
+nwi_ifstate_t
+nwi_ifstate_get_next(nwi_ifstate_t ifstate, int af);
+
+/*
+ * Function: nwi_ifstate_compare_rank
+ * Purpose:
+ *   Compare the relative rank of two nwi_ifstate_t objects.
+ *
+ *   The "rank" indicates the importance of the underlying interface.
+ *
+ * Returns:
+ *   0         if ifstate1 and ifstate2 are ranked equally
+ *  -1 if ifstate1 is ranked ahead of ifstate2
+ *   1 if ifstate2 is ranked ahead of ifstate1
+ */
+int
+nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2);
+
+/*
+ * Function: _nwi_state_ack
+ * Purpose:
+ *   Acknowledge receipt and any changes associated with the [new or
+ *   updated] network state.
+ */
+void
+_nwi_state_ack(nwi_state_t state, const char *bundle_id)
+       __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0);
+
+#endif
diff --git a/nwi/network_information_priv.c b/nwi/network_information_priv.c
new file mode 100644 (file)
index 0000000..7dfc706
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <arpa/inet.h>
+#include <notify.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <stdbool.h>
+#include "network_information_priv.h"
+#include <limits.h>
+
+sa_family_t nwi_af_list[] = {AF_INET, AF_INET6};
+
+static __inline__ unsigned int
+nwi_state_compute_size(unsigned int n)
+{
+       return (offsetof(nwi_state, nwi_ifstates[n]));
+
+}
+__private_extern__
+nwi_state_t
+nwi_state_copy_priv(nwi_state_t src)
+{
+       nwi_state_t dest = NULL;
+
+       if (src == NULL) {
+               return dest;
+       }
+
+       dest = malloc(src->size);
+
+       if (dest != NULL) {
+               bcopy(src, dest, src->size);
+
+               dest->ref = 1;
+       }
+       return dest;
+}
+
+__private_extern__
+nwi_state_t
+nwi_state_new(nwi_state_t old_state, int elems)
+{
+       nwi_state_t state = NULL;
+       int new_size;
+
+       if (old_state == NULL && elems == 0) {
+               return NULL;
+       }
+
+       /* Need to insert a last node for each of the v4/v6 list */
+       new_size = (elems != 0)?
+                       (sizeof(nwi_state)  + nwi_state_compute_size((elems+1) * 2)):0;
+
+       /* Should we reallocate? */
+       if (old_state != NULL) {
+               if (old_state->size >= new_size) {
+                       return (old_state);
+               }
+       }
+
+       state = malloc(new_size);
+       if (state == NULL) {
+               return NULL;
+       }
+
+       state->size = new_size;
+
+       /*
+        * v4 list is stored 0 to elems,
+        * v6 list is stored elems + 1 to 2 * elems + 2
+        */
+       state->ipv6_start = elems + 1;
+
+       if (old_state != NULL) {
+               state->ipv6_count = old_state->ipv6_count;
+               if (state->ipv6_count > 0) {
+                       bcopy((void*) &old_state->nwi_ifstates[old_state->ipv6_start],
+                             (void*) &state->nwi_ifstates[state->ipv6_start],
+                             old_state->ipv6_count * sizeof(nwi_ifstate));
+               }
+
+               state->ipv4_count = old_state->ipv4_count;
+
+               if (state->ipv4_count > 0) {
+                       bcopy((void*) old_state->nwi_ifstates,
+                             (void*) state->nwi_ifstates,
+                             old_state->ipv4_count * sizeof(nwi_ifstate));
+               }
+
+               free(old_state);
+       } else {
+               state->ipv4_count = 0;
+               state->ipv6_count = 0;
+       }
+       nwi_state_set_last(state, AF_INET);
+       nwi_state_set_last(state, AF_INET6);
+
+       state->ref = 1;
+       return state;
+}
+
+static inline
+nwi_ifstate_t nwi_ifstate_get_last(nwi_state_t state, int af, uint32_t** last)
+{
+       uint32_t*       count;
+       int             idx;
+
+       count = (af == AF_INET)
+               ?&state->ipv4_count:&state->ipv6_count;
+
+       idx = (af == AF_INET)
+               ?state->ipv4_count:(state->ipv6_start + state->ipv6_count);
+
+       *last = count;
+
+       return &state->nwi_ifstates[idx];
+
+}
+
+__private_extern__
+void
+nwi_insert_ifstate(nwi_state_t state,
+                  const char* ifname, int af,
+                  uint64_t flags, Rank rank,
+                  void* ifa)
+{
+       nwi_ifstate_t   ifstate;
+
+       /* Will only insert unique elements in the list */
+       ifstate = nwi_state_get_ifstate_with_name(state, af, ifname);
+
+       /* Already present, just ignore it */
+       if (ifstate != NULL) {
+               if (ifstate->rank < rank) {
+                       return;
+               }
+       }
+
+       if (ifstate == NULL) {
+               uint32_t        *last;
+
+               /* We need to append it as the last element */
+               ifstate = nwi_ifstate_get_last(state, af, &last);
+               strcpy(ifstate->ifname, ifname);
+               ifstate->af_alias = NULL;
+               ifstate->af = af;
+               ifstate->diff_ch = NULL;
+               (*last)++;
+       }
+
+       /* We need to update the address/rank/flag fields for the existing/new
+        * element */
+       if (ifa != NULL) {
+               switch (af) {
+                       case AF_INET:
+                               ifstate->iaddr = *((struct in_addr *) ifa);
+                               break;
+                       case AF_INET6:
+                               ifstate->iaddr6 = *((struct in6_addr *) ifa);
+                               break;
+                       default:
+                               break;
+               }
+
+       }
+
+       ifstate->rank = rank;
+       ifstate->flags = flags;
+
+       return;
+}
+
+__private_extern__
+void
+nwi_state_clear(nwi_state_t state, int af)
+{
+       uint32_t* count;
+
+       count = (af == AF_INET)
+               ?&state->ipv4_count:&state->ipv6_count;
+
+       *count = 0;
+       nwi_state_set_last(state, af);
+       return;
+
+}
+
+__private_extern__
+void
+nwi_state_set_last(nwi_state_t state, int af)
+{
+       int last_elem_idx;
+
+       if (state == NULL) {
+               return;
+       }
+
+       /* The last element is an element with the flags set as
+        * NWI_IFSTATE_FLAGS_NOT_IN_LIST */
+       last_elem_idx = (af == AF_INET)
+                       ?state->ipv4_count
+                       :(state->ipv6_start + state->ipv6_count);
+
+       state->nwi_ifstates[last_elem_idx].ifname[0] = '\0';
+       state->nwi_ifstates[last_elem_idx].flags
+           |= NWI_IFSTATE_FLAGS_NOT_IN_LIST;
+}
+
+__private_extern__
+void
+_nwi_state_dump(int level, nwi_state_t state)
+{
+       const char *            addr_str;
+       void *                  address;
+       int                     i;
+       char                    ntopbuf[INET6_ADDRSTRLEN];
+       nwi_ifstate_t           scan;
+
+
+       if (state == NULL) {
+               syslog(level, "<empty nwi_state>");
+               return;
+       }
+       syslog(level, "nwi_state = { gen = %llu size = %u #ipv4 = %u #ipv6 = %u }",
+              state->generation_count,
+              state->size,
+              state->ipv4_count,
+              state->ipv6_count);
+
+       if (state->ipv4_count) {
+               syslog(level, "IPv4:");
+               for (i = 0, scan = state->nwi_ifstates;
+                    i < state->ipv4_count; i++, scan++) {
+                       bool has_dns = (scan->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0;
+                       bool never = (scan->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0;
+
+                       address = nwi_ifstate_get_address(scan);
+                       addr_str =  inet_ntop(scan->af, address, ntopbuf, sizeof(ntopbuf));
+
+                       syslog(level, "    [%d]: %s%s%s%s rank %u iaddr: %s " ,
+                              i, scan->ifname, scan->diff_ch != NULL?scan->diff_ch:"",
+                              has_dns ? " dns" : "",
+                              never ? " never" : "",
+                              scan->rank,
+                              addr_str);
+               }
+       }
+       if (state->ipv6_count) {
+               syslog(level, "IPv6:");
+               for (i = 0, scan = state->nwi_ifstates + state->ipv6_start;
+                    i < state->ipv6_count; i++, scan++) {
+                       bool has_dns = (scan->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0;
+                       bool never = (scan->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0;
+
+                       address = nwi_ifstate_get_address(scan);
+                       addr_str =  inet_ntop(scan->af, address, ntopbuf, sizeof(ntopbuf));
+                       syslog(level, "    [%d]: %s%s%s%s rank %u iaddr6: %s ",
+                              i, scan->ifname, scan->diff_ch != NULL?scan->diff_ch:"",
+                              has_dns ? " dns" : "",
+                              never ? " never" : "",
+                              scan->rank,
+                              addr_str);
+               }
+       }
+       return;
+}
+
+
+#define        unchanged       ""
+#define added          "+"
+#define deleted                "-"
+#define changed                "!"
+
+__private_extern__
+void *
+nwi_ifstate_get_address(nwi_ifstate_t ifstate)
+{
+       return (void *)&ifstate->iaddr;
+}
+
+__private_extern__
+const char *
+nwi_ifstate_get_diff_str(nwi_ifstate_t ifstate)
+{
+       return ifstate->diff_ch;
+}
+
+static
+inline
+boolean_t
+nwi_ifstate_has_changed(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2)
+{
+       if (ifstate1->rank != ifstate2->rank) {
+               return TRUE;
+       }
+
+       if (ifstate1->flags != ifstate2->flags) {
+               return TRUE;
+       }
+
+       if (ifstate1->af == AF_INET) {
+               if (memcmp(&ifstate1->iaddr, &ifstate2->iaddr, sizeof(struct in_addr)) != 0) {
+                       return TRUE;
+               }
+       } else {
+               if (memcmp(&ifstate1->iaddr6, &ifstate2->iaddr6, sizeof(struct in6_addr)) != 0) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+static
+inline
+nwi_ifstate_t
+nwi_ifstate_append(nwi_state_t state, nwi_ifstate_t scan)
+{
+       nwi_ifstate_t   new_ifstate = NULL;
+       uint32_t        *last;
+
+       new_ifstate = nwi_ifstate_get_last(state, scan->af, &last);
+       memcpy(new_ifstate, scan, sizeof(*scan));
+       (*last)++;
+       return new_ifstate;
+}
+
+static
+inline
+void
+nwi_ifstate_set_diff_str(nwi_ifstate_t ifstate, const char * ch)
+{
+       ifstate->diff_ch = ch;
+}
+
+static
+void
+nwi_state_merge_added(nwi_state_t state, nwi_state_t old_state,
+                   nwi_state_t new_state)
+{
+       int idx;
+       nwi_ifstate_t scan;
+
+       /* Iterate through v4 and v6 list and annotate the diff flags */
+       for (idx = 0; idx < sizeof(nwi_af_list)/sizeof(nwi_af_list[0]); idx++) {
+               scan = nwi_state_get_first_ifstate(new_state, nwi_af_list[idx]);
+
+               while (scan != NULL) {
+                       nwi_ifstate_t   existing_ifstate, new_ifstate;
+                       const char*     ifname;
+
+                       ifname = nwi_ifstate_get_ifname(scan);
+
+                       existing_ifstate = nwi_state_get_ifstate_with_name(old_state, scan->af, ifname);
+
+                       /* Add the element that is not in the store */
+                       new_ifstate = nwi_ifstate_append(state, scan);
+
+                       /* These are potentially "added" elements unless they are
+                        * in the old list */
+                       nwi_ifstate_set_diff_str(new_ifstate, added);
+
+                       if (existing_ifstate != NULL) {
+                               if (nwi_ifstate_has_changed(existing_ifstate, new_ifstate) == TRUE) {
+                                       nwi_ifstate_set_diff_str(new_ifstate, changed);
+                               } else {
+                                       nwi_ifstate_set_diff_str(new_ifstate, unchanged);
+                               }
+                       }
+                       scan = nwi_ifstate_get_next(scan, scan->af);
+               }
+               nwi_state_set_last(state, nwi_af_list[idx]);
+       }
+
+       return;
+}
+
+static
+void
+nwi_state_merge_removed(nwi_state_t state, nwi_state_t old_state)
+{
+       int idx;
+       nwi_ifstate_t scan;
+
+       /* Iterate through v4 and v6 list and annotate the diff flags */
+       for (idx = 0; idx < sizeof(nwi_af_list)/sizeof(nwi_af_list[0]); idx++) {
+               scan = nwi_state_get_first_ifstate(old_state, nwi_af_list[idx]);
+
+               while (scan != NULL) {
+                       nwi_ifstate_t   existing_ifstate;
+                       const char*     ifname;
+
+                       ifname = nwi_ifstate_get_ifname(scan);
+
+                       existing_ifstate = nwi_state_get_ifstate_with_name(state, scan->af, ifname);
+
+                       /* Any elements that has not been added means that they are removed */
+                       if (existing_ifstate == NULL) {
+                               nwi_ifstate_t new_ifstate = nwi_ifstate_append(state, scan);
+                               nwi_ifstate_set_diff_str(new_ifstate, deleted);
+                       }
+                       scan = nwi_ifstate_get_next(scan, scan->af);
+               }
+               nwi_state_set_last(state, nwi_af_list[idx]);
+       }
+
+}
+
+
+__private_extern__
+nwi_state_t
+nwi_state_diff(nwi_state_t old_state, nwi_state_t new_state)
+{
+       nwi_state_t     diff;
+       int             total_count = 0;
+
+       if (old_state != NULL) {
+               total_count = old_state->ipv4_count + old_state->ipv6_count;
+       }
+
+       if (new_state != NULL) {
+               total_count += new_state->ipv4_count + new_state->ipv6_count;
+       }
+
+       if (total_count == 0) {
+               return NULL;
+       }
+
+       diff = nwi_state_new(NULL, total_count);
+
+       nwi_state_merge_added(diff, old_state,  new_state);
+       nwi_state_merge_removed(diff, old_state);
+
+       /* Diff consists of a nwi_state_t with annotated diff_ch's */
+       return diff;
+}
+
diff --git a/nwi/network_information_priv.h b/nwi/network_information_priv.h
new file mode 100644 (file)
index 0000000..3eb3c12
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _NETWORK_INFORMATION_PRIV_H_
+#define _NETWORK_INFORMATION_PRIV_H_
+
+#include <net/if.h>
+#include <stdint.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "network_information.h"
+
+__private_extern__
+sa_family_t nwi_af_list[2];
+
+#define NWI_IFSTATE_FLAGS_NOT_IN_LIST  0x8
+
+typedef uint32_t        Rank;
+
+typedef struct _nwi_ifstate {
+       char ifname[IFNAMSIZ];
+       uint64_t flags;
+       nwi_ifstate_t af_alias;
+       Rank rank;
+       int af;
+       union {
+               struct in_addr iaddr;
+               struct in6_addr iaddr6;
+       };
+       const char* diff_ch;
+} nwi_ifstate;
+
+/*
+ * nwi_state
+ *
+ *+---------------------------------------------+
+ *| generation_count                            |
+ *|                                             |
+ *----------------------------------------------+
+ *| size                                        |
+ *|                                             |
+ *|---------------------------------------------+
+ *| ipv4_count                                  |
+ *|                                             |
+ *|---------------------------------------------+
+ *| ipv6_count                                  |
+ *|                                             |
+ *|---------------------------------------------+
+ *| ipv6_start                                  |-------+
+ *|                                             |       |
+ *|---------------------------------------------+       |ipv6_start stores the index of the start of the v6 list.
+ *| ref                                         |       |
+ *|                                             |       |
+ *|---------------------------------------------+       |
+ *| IPv4 nwi_ifstates                           |       |
+ *|                                             |<------|-------+
+ *|       ...                                   |       |       |
+ *|---------------------------------------------+       |       |
+ *| Sentinel nwi_ifstates                       |       |       |
+ *|    flags =NWI_IFSTATE_FLAGS_RANK_NEVER)    |       |       | af_alias points to the same ifstate in the
+ *|                                             |       |       | opposite (v4 -> v6 and vice versa) af list.
+ *|---------------------------------------------+       |       |
+ *| IPv6 nwi_ifstates                           |<------+       |
+ *|                                             |<--------------+
+ *|       ...                                   |
+ *|---------------------------------------------+
+ *| Sentinel nwi_ifstates                       |
+ *|       flags =NWI_IFSTATE_FLAGS_RANK_NEVER)  |
+ *|                                             |
+ *|---------------------------------------------+
+ *
+ */
+typedef struct _nwi_state {
+       uint64_t generation_count;
+       uint32_t size;
+       uint32_t ipv4_count;
+       uint32_t ipv6_count;
+       uint32_t ipv6_start;
+       uint32_t ref;
+       nwi_ifstate nwi_ifstates[0];
+} nwi_state;
+
+static __inline__ int
+uint32_cmp(uint32_t a, uint32_t b)
+{
+       int             ret;
+       
+       if (a == b) {
+               ret = 0;
+       }
+       else if (a < b) {
+               ret = -1;
+       }
+       else {
+               ret = 1;
+       }
+       return (ret);
+}
+
+static __inline__ int
+RankCompare(Rank a, Rank b)
+{
+       return (uint32_cmp(a, b));
+}
+
+/*
+ * Function: nwi_state_get_ifstate_count
+ * Purpose:
+ *   Return the number of ifstate elements for the specified address family
+ *   'af'. 'af' is either AF_INET or AF_INET6.
+ *
+ *   Returns zero if there are no elements.
+ */
+static __inline__
+int
+nwi_state_get_ifstate_count(nwi_state_t state, int af)
+{
+       return (af == AF_INET)?state->ipv4_count:state->ipv6_count;
+}
+
+/*
+ *   The ifstate list is sorted in order of decreasing priority, with the
+ *   highest priority element appearing at index zero.
+ *
+ *   If 'idx' is outside of the bounds of the corresponding array, returns NULL.
+ */
+static __inline__
+nwi_ifstate_t
+nwi_state_get_ifstate_with_index(nwi_state_t state, int af, int idx)
+{
+       nwi_ifstate_t nwi_ifstate = NULL;
+       int i_idx = idx;
+
+       if (idx > nwi_state_get_ifstate_count(state, af)) {
+               return (nwi_ifstate);
+       }
+
+       if (af == AF_INET6) {
+               i_idx = idx + state->ipv6_start;
+       }
+
+       return &state->nwi_ifstates[i_idx];
+}
+
+/*
+ * Function: nwi_state_get_ifstate_with_name
+ * Purpose:
+ *   Return the ifstate for the specified ifstate for the specified address
+ *   family 'af'. 'af' is either AF_INET or AF_INET6.
+ *
+ *   Returns NULL if no such information exists.
+ */
+static __inline__
+nwi_ifstate_t
+nwi_state_get_ifstate_with_name(nwi_state_t state,
+                                int af, const char * name)
+{
+       int idx = 0;
+       int count;
+       nwi_ifstate_t ifstate = NULL;
+
+       if (state == NULL) {
+               return ifstate;
+       }
+
+       count = (af == AF_INET)
+       ?state->ipv4_count:state->ipv6_count;
+
+
+       while (idx < count) {
+               ifstate = nwi_state_get_ifstate_with_index(state, af, idx);
+               if (ifstate == NULL) {
+                       break;
+               }
+               if (strcmp(name,
+                          nwi_ifstate_get_ifname(ifstate)) == 0) {
+                       return (ifstate);
+               }
+               idx++;
+       }
+       return (NULL);
+}
+
+__private_extern__
+nwi_state_t
+nwi_state_new(nwi_state_t old_state, int elems);
+
+__private_extern__
+nwi_state_t
+nwi_state_copy_priv(nwi_state_t old_state);
+
+__private_extern__
+void
+nwi_insert_ifstate(nwi_state_t state, const char* ifname, int af,
+                  uint64_t flags, Rank rank,
+                  void * ifa);
+
+__private_extern__
+void
+nwi_state_clear(nwi_state_t state, int af);
+
+__private_extern__
+void
+nwi_state_set_last(nwi_state_t state, int af);
+
+__private_extern__
+nwi_state_t
+nwi_state_diff(nwi_state_t old_state, nwi_state_t new_state);
+
+__private_extern__
+void *
+nwi_ifstate_get_address(nwi_ifstate_t ifstate);
+
+__private_extern__
+const char *
+nwi_ifstate_get_diff_str(nwi_ifstate_t ifstate);
+
+__private_extern__
+_Bool
+_nwi_state_store(nwi_state_t state);
+
+__private_extern__
+nwi_state_t
+_nwi_state_copy(void);
+
+__private_extern__
+void
+_nwi_state_dump(int level, nwi_state_t state);
+
+#endif
index 7a89d377b183763dfb059ecd73a7fffd8c6f8d60..4d9e2780fef1526a18a8fea2b3beb22c9bb334ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -109,7 +109,7 @@ static void *
 __loadSecurity(void) {
        static void *image = NULL;
        if (NULL == image) {
-               const char      *framework              = "/System/Library/Frameworks/Security.framework/Versions/A/Security";
+               const char      *framework              = "/System/Library/Frameworks/Security.framework/Security";
                struct stat     statbuf;
                const char      *suffix                 = getenv("DYLD_IMAGE_SUFFIX");
                char            path[MAXPATHLEN];
@@ -181,53 +181,58 @@ main(int argc, char **argv)
 
        /* process any arguments */
 
-       while ((opt = getopt_long(argc, argv, "dvn", longopts, NULL)) != -1)
+       while ((opt = getopt_long(argc, argv, "dvn", longopts, NULL)) != -1) {
                switch(opt) {
-               case 'd':
-                       _sc_debug = TRUE;
-                       _sc_log   = FALSE;      /* enable framework logging */
-                       break;
-               case 'v':
-                       _sc_verbose = TRUE;
-                       break;
-               case 'n':
-                       apply = FALSE;
-                       break;
-               case '?':
-               default :
-                       usage(command);
+                       case 'd':
+                               _sc_debug = TRUE;
+                               _sc_log   = FALSE;      /* enable framework logging */
+                               break;
+                       case 'v':
+                               _sc_verbose = TRUE;
+                               break;
+                       case 'n':
+                               apply = FALSE;
+                               break;
+                       case '?':
+                       default :
+                               usage(command);
+               }
        }
        argc -= optind;
        argv += optind;
 
        prefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("/%@/"), kSCPrefSets);
 
-       newSet = (argc == 1)
-                       ? CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman)
-                       : CFRetain(CFSTR(""));
+       if (argc == 1) {
+               newSet = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
 
-       prefs = SCPreferencesCreate(NULL, CFSTR("Select Set Command"), NULL);
-       if (prefs == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("SCPreferencesCreate() failed\n"));
-               exit (1);
-       }
+               /* check if a full path to the new "set" was specified */
+               if ((CFStringGetLength(newSet) > 0) && CFStringHasPrefix(newSet, prefix)) {
+                       CFRange                 range;
+                       CFMutableStringRef      str;
 
-       /* check if a full path to the new "set" was specified */
-       if ((CFStringGetLength(newSet) > 0) && CFStringHasPrefix(newSet, prefix)) {
-               CFRange                 range;
-               CFMutableStringRef      str;
+                       str = CFStringCreateMutableCopy(NULL, 0, newSet);
+                       CFRelease(newSet);
 
-               str = CFStringCreateMutableCopy(NULL, 0, newSet);
-               CFStringDelete(str, CFRangeMake(0, CFStringGetLength(prefix)));
+                       CFStringDelete(str, CFRangeMake(0, CFStringGetLength(prefix)));
+                       newSet = CFStringCreateCopy(NULL, newSet);
+                       CFRelease(str);
 
-               range = CFStringFind(str, CFSTR("/"), 0);
-               if (range.location != kCFNotFound) {
-                       SCPrint(TRUE, stderr, CFSTR("Set \"%@\" not available\n."), newSet);
-                       exit (1);
+                       range = CFStringFind(newSet, CFSTR("/"), 0);
+                       if (range.location != kCFNotFound) {
+                               SCPrint(TRUE, stderr, CFSTR("Set \"%@\" not available\n."), newSet);
+                               exit (1);
+                       }
                }
+       } else {
+               newSet = CFRetain(CFSTR(""));
+       }
 
-               CFRelease(newSet);
-               newSet = str;
+
+       prefs = SCPreferencesCreate(NULL, CFSTR("Select Set Command"), NULL);
+       if (prefs == NULL) {
+               SCPrint(TRUE, stderr, CFSTR("SCPreferencesCreate() failed\n"));
+               exit (1);
        }
 
        sets = SCPreferencesGetValue(prefs, kSCPrefSets);
index 84d96d28e633c337a5127a484ca50b880a91d267..76fd819b716f1771ff6c5b4a2f320db7ea5dfb51 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include "cache.h"
 
 
+#pragma mark -
+#pragma mark SCDynamicStore "cache"
+
+
+static Boolean                 use_cache       = FALSE;
+
+static CFMutableDictionaryRef  cached_keys     = NULL;
+static CFMutableDictionaryRef  cached_set      = NULL;
+static CFMutableArrayRef       cached_removals = NULL;
+static CFMutableArrayRef       cached_notifys  = NULL;
+
+
+static void
+cache_open(void)
+{
+       if (use_cache) {
+               // if we are already using the cache
+               cache_close();
+       }
+
+       cached_keys     = CFDictionaryCreateMutable(NULL,
+                                                   0,
+                                                   &kCFTypeDictionaryKeyCallBacks,
+                                                   &kCFTypeDictionaryValueCallBacks);
+       cached_set      = CFDictionaryCreateMutable(NULL,
+                                                   0,
+                                                   &kCFTypeDictionaryKeyCallBacks,
+                                                   &kCFTypeDictionaryValueCallBacks);
+       cached_removals = CFArrayCreateMutable(NULL,
+                                              0,
+                                              &kCFTypeArrayCallBacks);
+       cached_notifys  = CFArrayCreateMutable(NULL,
+                                              0,
+                                              &kCFTypeArrayCallBacks);
+
+       use_cache = TRUE;
+       return;
+}
+
+
+static CFPropertyListRef
+cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
+{
+       CFPropertyListRef       value;
+
+       value = CFDictionaryGetValue(cached_set, key);
+       if (value) {
+               // if we have "set" a new value
+               return (CFRetain(value));
+       }
+
+       if (CFArrayContainsValue(cached_removals,
+                                CFRangeMake(0, CFArrayGetCount(cached_removals)),
+                                key)) {
+               // if we have "removed" the key
+               _SCErrorSet(kSCStatusNoKey);
+               return NULL;
+       }
+
+       value = CFDictionaryGetValue(cached_keys, key);
+       if (value) {
+               // if we have a cached value
+               return (CFRetain(value));
+       }
+
+       value = SCDynamicStoreCopyValue(store, key);
+       if (value) {
+               CFDictionarySetValue(cached_keys, key, value);
+       }
+
+       return value;
+}
+
+
+static void
+cache_SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
+{
+       CFIndex i;
+
+       i = CFArrayGetFirstIndexOfValue(cached_removals,
+                                       CFRangeMake(0, CFArrayGetCount(cached_removals)),
+                                       key);
+       if (i != kCFNotFound) {
+               // if previously "removed"
+               CFArrayRemoveValueAtIndex(cached_removals, i);
+       }
+
+       CFDictionarySetValue(cached_set, key, value);
+
+       return;
+}
+
+static void
+cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
+{
+       CFDictionaryRemoveValue(cached_set, key);
+
+       if (!CFArrayContainsValue(cached_removals,
+                                 CFRangeMake(0, CFArrayGetCount(cached_removals)),
+                                 key)) {
+               CFArrayAppendValue(cached_removals, key);
+       }
+
+       return;
+}
+
+
+static void
+cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key)
+{
+       if (!CFArrayContainsValue(cached_notifys,
+                                 CFRangeMake(0, CFArrayGetCount(cached_notifys)),
+                                 key)) {
+               CFArrayAppendValue(cached_notifys, key);
+       }
+
+       return;
+}
+
+
+static void
+cache_write(SCDynamicStoreRef store)
+{
+       if ((CFDictionaryGetCount(cached_set) > 0) ||
+           (CFArrayGetCount(cached_removals) > 0) ||
+           (CFArrayGetCount(cached_notifys)  > 0)) {
+               if (!SCDynamicStoreSetMultiple(store,
+                                              cached_set,
+                                              cached_removals,
+                                              cached_notifys)) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               }
+       }
+
+       return;
+}
+
+
+__private_extern__
+void
+cache_close(void)
+{
+       if (!use_cache) {
+               return;
+       }
+
+       CFRelease(cached_keys);
+       CFRelease(cached_set);
+       CFRelease(cached_removals);
+       CFRelease(cached_notifys);
+
+       use_cache = FALSE;
+       return;
+}
+
+
+#pragma mark -
+#pragma mark SCDynamicStore operations
+
+
+__private_extern__
+void
+do_block(int argc, char **argv)
+{
+       Boolean         enable  = FALSE;
+
+       if (argc >= 1) {
+               if        ((strcasecmp(argv[0], "begin") == 0) ||
+                          (strcasecmp(argv[0], "start") == 0) ||
+                          (strcasecmp(argv[0], "on"   ) == 0) ||
+                          (strcasecmp(argv[0], "1"    ) == 0)) {
+                       enable = TRUE;
+               } else if ((strcasecmp(argv[0], "end"  ) == 0) ||
+                          (strcasecmp(argv[0], "stop" ) == 0) ||
+                          (strcasecmp(argv[0], "off"  ) == 0) ||
+                          (strcasecmp(argv[0], "0"    ) == 0)) {
+                       enable = FALSE;
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("invalid value\n"));
+                       return;
+               }
+       } else {
+               enable = !use_cache;    // toggle
+       }
+
+       if (enable) {
+               // begin block of SCDynamicStore operations
+               if (use_cache) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(kSCStatusLocked));
+                       return;
+               }
+
+               SCPrint(TRUE, stdout, CFSTR("Begin block of SCDynamicStore operations\n"));
+
+               cache_open();
+       } else {
+               CFIndex n;
+
+               // end block of SCDynamicStore operations
+               if (!use_cache) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(kSCStatusNeedLock));
+                       return;
+               }
+
+               n = CFDictionaryGetCount(cached_keys) +
+                   CFArrayGetCount(cached_removals)  +
+                   CFArrayGetCount(cached_notifys);
+               SCPrint(TRUE, stdout,
+                       CFSTR("End block of SCDynamicStore operations%s\n"),
+                       (n > 0) ? ", posting changes" : "");
+               if (n > 0) {
+                       cache_write(store);
+               }
+               cache_close();
+       }
+
+       return;
+}
+
+
 static CFComparisonResult
 sort_keys(const void *p1, const void *p2, void *context) {
        CFStringRef key1 = (CFStringRef)p1;
@@ -45,6 +265,9 @@ sort_keys(const void *p1, const void *p2, void *context) {
 }
 
 
+#define        N_QUICK 64
+
+
 __private_extern__
 void
 do_list(int argc, char **argv)
@@ -64,10 +287,37 @@ do_list(int argc, char **argv)
        if (list == NULL) {
                if (SCError() != kSCStatusOK) {
                        SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+                       return;
                } else {
+                   if (!use_cache) {
                        SCPrint(TRUE, stdout, CFSTR("  no keys.\n"));
+                       return;
+                   } else {
+                       CFIndex n;
+
+                       n = CFDictionaryGetCount(cached_set);
+                       if (n > 0){
+                               const void *    cachedKeys_q[N_QUICK];
+                               const void **   cachedKeys      = cachedKeys_q;
+
+                               if (n > (CFIndex)(sizeof(cachedKeys_q) / sizeof(CFStringRef))) {
+                                       cachedKeys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
+                               }
+                               CFDictionaryGetKeysAndValues(cached_set, cachedKeys, NULL);
+                               list = CFArrayCreate(NULL, cachedKeys, n, &kCFTypeArrayCallBacks);
+                               if (cachedKeys != cachedKeys_q) {
+                                       CFAllocatorDeallocate(NULL, cachedKeys);
+                               }
+                       } else {
+                               SCPrint(TRUE, stdout, CFSTR("  no keys.\n"));
+                               return;
+                       }
+                   }
                }
-               return;
+       } else if (use_cache &&
+                  ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0))) {
+               SCPrint(TRUE, stdout,
+                       CFSTR("  Note: SCDynamicStore transactions in progress, key list (below) may be out of date.\n\n"));
        }
 
        listCnt = CFArrayGetCount(list);
@@ -104,12 +354,41 @@ do_add(int argc, char **argv)
        key    = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
 
        if (argc < 2) {
-               if (!SCDynamicStoreAddValue(store, key, value)) {
-                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               if (!use_cache) {
+                       if (!SCDynamicStoreAddValue(store, key, value)) {
+                               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+                       }
+               } else {
+                       CFTypeRef       val;
+
+                       val = cache_SCDynamicStoreCopyValue(store, key);
+                       if (val != NULL) {
+                               CFRelease(val);
+                               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(kSCStatusKeyExists));
+                       } else {
+                               cache_SCDynamicStoreSetValue(store, key, value);
+                       }
                }
        } else {
-               if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
-                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               if (!use_cache) {
+                       if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
+                               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+                       }
+               } else {
+                       CFTypeRef       val;
+
+                       val = cache_SCDynamicStoreCopyValue(store, key);
+                       if (val != NULL) {
+                               CFRelease(val);
+                               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(kSCStatusKeyExists));
+                       } else {
+                               if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
+                                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+                               } else {
+                                       // and save the temp value in the cache too!
+                                       cache_SCDynamicStoreSetValue(store, key, value);
+                               }
+                       }
                }
        }
 
@@ -126,7 +405,11 @@ do_get(int argc, char **argv)
        CFPropertyListRef       newValue;
 
        key      = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
-       newValue = SCDynamicStoreCopyValue(store, key);
+       if (!use_cache) {
+               newValue = SCDynamicStoreCopyValue(store, key);
+       } else {
+               newValue = cache_SCDynamicStoreCopyValue(store, key);
+       }
        CFRelease(key);
        if (newValue == NULL) {
                SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
@@ -149,8 +432,12 @@ do_set(int argc, char **argv)
        CFStringRef     key;
 
        key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
-       if (!SCDynamicStoreSetValue(store, key, value)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+       if (!use_cache) {
+               if (!SCDynamicStoreSetValue(store, key, value)) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               }
+       } else {
+               cache_SCDynamicStoreSetValue(store, key, value);
        }
        CFRelease(key);
        return;
@@ -167,12 +454,51 @@ do_show(int argc, char **argv)
        key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
 
        if (argc == 1) {
-               newValue = SCDynamicStoreCopyValue(store, key);
+               if (!use_cache) {
+                       newValue = SCDynamicStoreCopyValue(store, key);
+               } else {
+                       newValue = cache_SCDynamicStoreCopyValue(store, key);
+               }
        } else {
                CFArrayRef      patterns;
 
                patterns = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
-               newValue = SCDynamicStoreCopyMultiple(store, NULL, patterns);
+               if (!use_cache) {
+                       newValue = SCDynamicStoreCopyMultiple(store, NULL, patterns);
+               } else {
+                       CFArrayRef              keys;
+                       CFMutableDictionaryRef  newDict;
+
+                       newDict = CFDictionaryCreateMutable(NULL,
+                                                           0,
+                                                           &kCFTypeDictionaryKeyCallBacks,
+                                                           &kCFTypeDictionaryValueCallBacks);
+                       keys = SCDynamicStoreCopyKeyList(store, key);
+                       if (keys != NULL) {
+                               CFIndex         i;
+                               CFIndex         n;
+
+                               n = CFArrayGetCount(keys);
+                               for (i = 0; i < n; i++) {
+                                       CFStringRef     storeKey;
+                                       CFTypeRef       storeVal;
+
+                                       storeKey = CFArrayGetValueAtIndex(keys, i);
+                                       storeVal = cache_SCDynamicStoreCopyValue(store, storeKey);
+                                       if (storeVal != NULL) {
+                                               CFDictionarySetValue(newDict, storeKey, storeVal);
+                                               CFRelease(storeVal);
+                                       }
+                               }
+                               CFRelease(keys);
+                       }
+
+                       if ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0)) {
+                               SCPrint(TRUE, stdout, CFSTR("  Note: SCDynamicStore locked, keys included (below) may be out of date.\n\n"));
+                       }
+
+                       newValue = newDict;
+               }
                CFRelease(patterns);
        }
 
@@ -195,8 +521,12 @@ do_remove(int argc, char **argv)
        CFStringRef     key;
 
        key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
-       if (!SCDynamicStoreRemoveValue(store, key)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+       if (!use_cache) {
+               if (!SCDynamicStoreRemoveValue(store, key)) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               }
+       } else {
+               cache_SCDynamicStoreRemoveValue(store, key);
        }
        CFRelease(key);
        return;
@@ -210,23 +540,12 @@ do_notify(int argc, char **argv)
        CFStringRef     key;
 
        key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
-       if (!SCDynamicStoreNotifyValue(store, key)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
-       }
-       CFRelease(key);
-       return;
-}
-
-
-__private_extern__
-void
-do_touch(int argc, char **argv)
-{
-       CFStringRef     key;
-
-       key    = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
-       if (!SCDynamicStoreTouchValue(store, key)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+       if (!use_cache) {
+               if (!SCDynamicStoreNotifyValue(store, key)) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               }
+       } else {
+               cache_SCDynamicStoreNotifyValue(store, key);
        }
        CFRelease(key);
        return;
index acace785088d5ebd5787f1e6a5d37fc7f7c5b765..ef14ef27d005982485c689f16defd295d044e61f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #ifndef _CACHE_H
 #define _CACHE_H
 
+#include <Availability.h>
+#include <TargetConditionals.h>
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
+void   cache_close             (void);
+
+void   do_block                (int argc, char **argv);
+
 void   do_list                 (int argc, char **argv);
 void   do_add                  (int argc, char **argv);
 void   do_get                  (int argc, char **argv);
@@ -45,7 +51,6 @@ void  do_set                  (int argc, char **argv);
 void   do_show                 (int argc, char **argv);
 void   do_remove               (int argc, char **argv);
 void   do_notify               (int argc, char **argv);
-void   do_touch                (int argc, char **argv);
 
 __END_DECLS
 
index 59d929d0aeb355eedd3e0ee2d329913da654b8cf..5b93ff67c80a3fbab654151e630db6b46095776a 100644 (file)
@@ -76,7 +76,7 @@ const cmdInfo commands_store[] = {
 
        { "d.add",      2,      101,    do_dictSetKey,          1,      0,
                " d.add key [*#?] val [v2 ...]  : add information to dictionary\n"
-               "       (*=array, #=number, ?=boolean)"                                         },
+               "       (*=array, #=number, ?=boolean, %=hex data)"                             },
 
        { "d.remove",   1,      1,      do_dictRemoveKey,       1,      0,
                " d.remove key                  : remove key from dictionary"                   },
@@ -89,11 +89,8 @@ const cmdInfo commands_store[] = {
        { "close",      0,      0,      do_close,               2,      1,
                " close                         : close current \"configd\" session"            },
 
-       { "lock",       0,      0,      do_lock,                3,      1,
-               " lock                          : locks write access to data store"             },
-
-       { "unlock",     0,      0,      do_unlock,              3,      1,
-               " unlock                        : unlocks write access to data store"           },
+       { "block",      0,      1,      do_block,               3,      1,
+               " block [\"begin\" | \"end\"]     : block multiple data store transactions"     },
 
        { "list",       0,      2,      do_list,                4,      0,
                " list [pattern]                : list keys in data store"                      },
@@ -116,9 +113,6 @@ const cmdInfo commands_store[] = {
        { "notify",     1,      1,      do_notify,              4,      0,
                " notify key                    : notify key in data store"                     },
 
-       { "touch",      1,      1,      do_touch,               4,      1,
-               " touch key                     : touch key in data store"                      },
-
        { "n.list",     0,      1,      do_notify_list,         5,      0,
                " n.list [\"pattern\"]            : list notification keys"                     },
 
@@ -137,9 +131,6 @@ const cmdInfo commands_store[] = {
        { "n.wait",     0,      0,      do_notify_wait,         5,      2,
                " n.wait                        : wait for changes"                             },
 
-       { "n.callback", 0,      1,      do_notify_callback,     5,      2,
-               " n.callback [\"verbose\"]        : watch for changes"                          },
-
        { "n.signal",   1,      2,      do_notify_signal,       5,      2,
                " n.signal sig [pid]            : signal changes"                               },
 
@@ -272,7 +263,7 @@ const cmdInfo commands_prefs[] = {
 
        { "d.add",      2,      101,    do_dictSetKey,          1,      0,
                " d.add key [*#?] val [v2 ...]  : add information to dictionary\n"
-               "       (*=array, #=number, ?=boolean)"                                         },
+               "       (*=array, #=number, ?=boolean, %=hex data)"                             },
 
        { "d.remove",   1,      1,      do_dictRemoveKey,       1,      0,
                " d.remove key                  : remove key from dictionary"                   },
index 396e3ab5add00be21c4ce3d29dfe77a86d9a4b7d..790aab408f987e115fb47f1d0fcdf7f75acad79b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -79,6 +79,7 @@ do_dictSetKey(int argc, char **argv)
        CFMutableArrayRef       array           = NULL;
        Boolean                 doArray         = FALSE;
        Boolean                 doBoolean       = FALSE;
+       Boolean                 doData          = FALSE;
        Boolean                 doNumeric       = FALSE;
        CFStringRef             key;
        CFMutableDictionaryRef  newValue;
@@ -106,6 +107,9 @@ do_dictSetKey(int argc, char **argv)
                } else if (strcmp(argv[0], "?") == 0) {
                        /* if boolean values requested */
                        doBoolean = TRUE;
+               } else if (strcmp(argv[0], "%") == 0) {
+                       /* if [hex] data values requested */
+                       doData = TRUE;
                } else if (strcmp(argv[0], "#") == 0) {
                        /* if numeric values requested */
                        doNumeric = TRUE;
@@ -148,6 +152,51 @@ do_dictSetKey(int argc, char **argv)
                                CFRelease(key);
                                return;
                        }
+               } else if (doData) {
+                       uint8_t                 *bytes;
+                       CFMutableDataRef        data;
+                       int                     i;
+                       int                     j;
+                       int                     n;
+
+                       n = strlen(argv[0]);
+                       if ((n % 2) == 1) {
+                               SCPrint(TRUE, stdout, CFSTR("d.add: not enough bytes.\n"));
+                               if (doArray) CFRelease(array);
+                               CFRelease(key);
+                               return;
+                       }
+
+                       data = CFDataCreateMutable(NULL, (n / 2));
+                       CFDataSetLength(data, (n / 2));
+
+                       bytes = (uint8_t *)CFDataGetBytePtr(data);
+                       for (i = 0, j = 0; i < n; i += 2, j++) {
+                               unsigned long   byte;
+                               char            *end;
+                               char            str[3]  = { 0 };
+
+                               str[0] = argv[0][i];
+                               str[1] = argv[0][i + 1];
+                               errno = 0;
+                               byte = strtoul(str, &end, 16);
+                               if ((*end != '\0') || (errno != 0)) {
+                                       CFRelease(data);
+                                       data = NULL;
+                                       break;
+                               }
+
+                               bytes[j] = byte;
+                       }
+
+                       if (data == NULL) {
+                               SCPrint(TRUE, stdout, CFSTR("d.add: invalid data.\n"));
+                               if (doArray) CFRelease(array);
+                               CFRelease(key);
+                               return;
+                       }
+
+                       val = data;
                } else if (doNumeric) {
                        int     intValue;
 
index 48806d0794cc485bdfd44ab4164c93b02dcaf848..551289cff59394c458efb77d136d7f7b84795da6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * - initial revision
  * February 8, 2011                    Kevin Wells <kcw@apple.com>
  * - added "select" command
+ * January 2012                                Kevin Wells <kcw@apple.com>
+ * - added arguments to "start" command to pass authentication credentials
+ * - "show" now takes a service name as an alternative to a service ID
+ * - fixes a bug whereby "IPv4" was being displayed as a subtype to IPsec services
+ * - improved format of "list" output
+ * - general cleanup of error messages and some variable names
  */
 
 
 
 #include <sys/time.h>
 
+CFStringRef                    username = NULL;
+CFStringRef                    password = NULL;
+CFStringRef                    sharedsecret = NULL;
 
-static SCNetworkConnectionRef  connectionRef   = NULL;
+static SCNetworkConnectionRef  connection      = NULL;
 static int                     n_callback      = 0;
 
 
@@ -56,19 +65,18 @@ my_CFRelease(void *t)
 }
 
 /* -----------------------------------------------------------------------------
------------------------------------------------------------------------------ */
-static CFStringRef
-nc_copy_serviceID(int argc, char **argv)
-{
-       CFStringRef             serviceIDRef    = NULL;
+ ----------------------------------------------------------------------------- */
+static void
+nc_get_service_type_and_subtype(SCNetworkServiceRef service, CFStringRef *iftype, CFStringRef *ifsubtype) {
+       SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(service);
+       SCNetworkInterfaceRef child = SCNetworkInterfaceGetInterface(interface);
 
-       if (argc == 0) {
-               serviceIDRef = _copyStringFromSTDIN();
-       } else {
-               serviceIDRef = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+       *iftype = SCNetworkInterfaceGetInterfaceType(interface);
+       *ifsubtype = NULL;
+       if (CFEqual(*iftype, kSCNetworkInterfaceTypePPP) ||
+           CFEqual(*iftype, kSCNetworkInterfaceTypeVPN)) {
+           *ifsubtype = (child != NULL) ? SCNetworkInterfaceGetInterfaceType(child) : NULL;
        }
-
-       return serviceIDRef;
 }
 
 /* -----------------------------------------------------------------------------
@@ -114,19 +122,40 @@ nc_copy_service(SCNetworkSetRef set, CFStringRef identifier)
                        } else {
                                // if multiple services match
                                selected = NULL;
-                               SCPrint(TRUE, stdout, CFSTR("multiple services match\n"));
+                               SCPrint(TRUE, stderr, CFSTR("Multiple services match\n"));
                                goto done;
                        }
                }
        }
 
-    done :
+done :
 
        if (selected != NULL) CFRetain(selected);
        if (services != NULL) CFRelease(services);
        return selected;
 }
 
+/* -----------------------------------------------------------------------------
+ ----------------------------------------------------------------------------- */
+static SCNetworkServiceRef
+nc_copy_service_from_arguments(int argc, char **argv, SCNetworkSetRef set) {
+       CFStringRef             serviceID       = NULL;
+       SCNetworkServiceRef     service         = NULL;
+
+       if (argc == 0) {
+               serviceID = _copyStringFromSTDIN();
+       } else {
+               serviceID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+       }
+       if (serviceID == NULL) {
+               SCPrint(TRUE, stderr, CFSTR("No service ID specified\n"));
+               return NULL;
+       }
+       service = nc_copy_service(set, serviceID);
+       my_CFRelease(&serviceID);
+       return service;
+}
+
 
 /* -----------------------------------------------------------------------------
 ----------------------------------------------------------------------------- */
@@ -194,18 +223,8 @@ nc_create_connection(int argc, char **argv, Boolean exit_on_failure)
 {
        SCNetworkConnectionContext      context = { 0, &n_callback, NULL, NULL, NULL };
        SCNetworkServiceRef             service;
-       CFStringRef                     serviceIDRef;
 
-       serviceIDRef = nc_copy_serviceID(argc, argv);
-       if (serviceIDRef == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("No service identifier\n"));
-               if (exit_on_failure)
-                       exit(1);
-               return;
-       }
-
-       service = nc_copy_service(NULL, serviceIDRef);
-       CFRelease(serviceIDRef);
+       service = nc_copy_service_from_arguments(argc, argv, NULL);
        if (service == NULL) {
                SCPrint(TRUE, stderr, CFSTR("No service\n"));
                if (exit_on_failure)
@@ -213,9 +232,10 @@ nc_create_connection(int argc, char **argv, Boolean exit_on_failure)
                return;
        }
 
-       connectionRef = SCNetworkConnectionCreateWithService(NULL, service, nc_callback, &context);
-       if (connectionRef == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("nc_create_connection SCNetworkConnectionCreateWithServiceID() failed to create connectionRef: %s\n"), SCErrorString(SCError()));
+       connection = SCNetworkConnectionCreateWithService(NULL, service, nc_callback, &context);
+       CFRelease(service);
+       if (connection == NULL) {
+               SCPrint(TRUE, stderr, CFSTR("Could not create connection: %s\n"), SCErrorString(SCError()));
                if (exit_on_failure)
                        exit(1);
                return;
@@ -227,7 +247,7 @@ nc_create_connection(int argc, char **argv, Boolean exit_on_failure)
 static void
 nc_release_connection()
 {
-       my_CFRelease(&connectionRef);
+       my_CFRelease(&connection);
 }
 
 /* -----------------------------------------------------------------------------
@@ -235,10 +255,76 @@ nc_release_connection()
 static void
 nc_start(int argc, char **argv)
 {
+       CFMutableDictionaryRef          userOptions = NULL;
+       CFStringRef                     iftype = NULL;
+       CFStringRef                     ifsubtype = NULL;
+       SCNetworkServiceRef             service = NULL;
+
        nc_create_connection(argc, argv, TRUE);
 
-       SCNetworkConnectionStart(connectionRef, 0, TRUE);
+       service = SCNetworkConnectionGetService(connection);
+       nc_get_service_type_and_subtype(service, &iftype, &ifsubtype);
+
+       userOptions = CFDictionaryCreateMutable(NULL, 0,
+                                               &kCFTypeDictionaryKeyCallBacks,
+                                               &kCFTypeDictionaryValueCallBacks);
 
+       Boolean isL2TP = (CFEqual(iftype, kSCEntNetPPP) &&
+                         (ifsubtype != NULL) && CFEqual(ifsubtype, kSCValNetInterfaceSubTypeL2TP));
+
+       if (CFEqual(iftype, kSCEntNetPPP)) {
+               CFMutableDictionaryRef pppEntity  = CFDictionaryCreateMutable(NULL, 0,
+                                                                          &kCFTypeDictionaryKeyCallBacks,
+                                                                          &kCFTypeDictionaryValueCallBacks);
+
+               if (username != NULL) {
+                       CFDictionarySetValue(pppEntity, kSCPropNetPPPAuthName, username);
+               }
+               if (password != NULL) {
+                       CFDictionarySetValue(pppEntity, kSCPropNetPPPAuthPassword, password);
+               }
+               CFDictionarySetValue(userOptions, kSCEntNetPPP, pppEntity);
+               my_CFRelease(&pppEntity);
+       }
+       if (CFEqual(iftype, kSCEntNetIPSec) || isL2TP) {
+               CFMutableDictionaryRef ipsecEntity  = CFDictionaryCreateMutable(NULL, 0,
+                                                                          &kCFTypeDictionaryKeyCallBacks,
+                                                                          &kCFTypeDictionaryValueCallBacks);
+               if (!isL2TP) {
+                       if (username != NULL) {
+                               CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecXAuthName, username);
+                       }
+                       if (password != NULL) {
+                               CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecXAuthPassword, password);
+                       }
+               }
+               if (sharedsecret != NULL) {
+                       CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecSharedSecret, sharedsecret);
+               }
+               CFDictionarySetValue(userOptions, kSCEntNetIPSec, ipsecEntity);
+               my_CFRelease(&ipsecEntity);
+       }
+       if (CFEqual(iftype, kSCEntNetVPN)) {
+               CFMutableDictionaryRef vpnEntity  = CFDictionaryCreateMutable(NULL, 0,
+                                                                          &kCFTypeDictionaryKeyCallBacks,
+                                                                          &kCFTypeDictionaryValueCallBacks);
+               if (username != NULL) {
+                       CFDictionarySetValue(vpnEntity, kSCPropNetVPNAuthName, username);
+               }
+               if (password != NULL) {
+                       CFDictionarySetValue(vpnEntity, kSCPropNetVPNAuthPassword, password);
+               }
+               CFDictionarySetValue(userOptions, kSCEntNetVPN, vpnEntity);
+               my_CFRelease(&vpnEntity);
+       }
+       // If it doesn't match any VPN type, fail silently
+
+       if (!SCNetworkConnectionStart(connection, userOptions, TRUE)) {
+               SCPrint(TRUE, stderr, CFSTR("Could not start connection: %s\n"), SCErrorString(SCError()));
+               exit(1);
+       };
+
+       CFRelease(userOptions);
        nc_release_connection();
        exit(0);
 }
@@ -250,7 +336,10 @@ nc_stop(int argc, char **argv)
 {
        nc_create_connection(argc, argv, TRUE);
 
-       SCNetworkConnectionStop(connectionRef, TRUE);
+       if (!SCNetworkConnectionStop(connection, TRUE)) {
+               SCPrint(TRUE, stderr, CFSTR("Could not stop connection: %s\n"), SCErrorString(SCError()));
+               exit(1);
+       };
 
        nc_release_connection();
        exit(0);
@@ -263,7 +352,7 @@ nc_suspend(int argc, char **argv)
 {
        nc_create_connection(argc, argv, TRUE);
 
-       SCNetworkConnectionSuspend(connectionRef);
+       SCNetworkConnectionSuspend(connection);
 
        nc_release_connection();
        exit(0);
@@ -276,7 +365,7 @@ nc_resume(int argc, char **argv)
 {
        nc_create_connection(argc, argv, TRUE);
 
-       SCNetworkConnectionResume(connectionRef);
+       SCNetworkConnectionResume(connection);
 
        nc_release_connection();
        exit(0);
@@ -291,8 +380,8 @@ nc_status(int argc, char **argv)
 
        nc_create_connection(argc, argv, TRUE);
 
-       status = SCNetworkConnectionGetStatus(connectionRef);
-       nc_callback(connectionRef, status, NULL);
+       status = SCNetworkConnectionGetStatus(connection);
+       nc_callback(connection, status, NULL);
 
        nc_release_connection();
        exit(0);
@@ -305,21 +394,21 @@ nc_watch(int argc, char **argv)
 
        nc_create_connection(argc, argv, TRUE);
 
-       status = SCNetworkConnectionGetStatus(connectionRef);
+       status = SCNetworkConnectionGetStatus(connection);
 
        // report initial status
        n_callback = 0;
-       nc_callback(connectionRef, status, &n_callback);
+       nc_callback(connection, status, &n_callback);
 
        // setup watcher
        if (doDispatch) {
-               if (!SCNetworkConnectionSetDispatchQueue(connectionRef, dispatch_get_current_queue())) {
-                       printf("SCNetworkConnectionSetDispatchQueue() failed: %s\n", SCErrorString(SCError()));
+               if (!SCNetworkConnectionSetDispatchQueue(connection, dispatch_get_current_queue())) {
+                       SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError()));
                        exit(1);
                }
        } else {
-               if (!SCNetworkConnectionScheduleWithRunLoop(connectionRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
-                       printf("SCNetworkConnectinScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError()));
+               if (!SCNetworkConnectionScheduleWithRunLoop(connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
+                       SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError()));
                        exit(1);
                }
        }
@@ -340,7 +429,7 @@ nc_statistics(int argc, char **argv)
 
        nc_create_connection(argc, argv, TRUE);
 
-       stats_dict = SCNetworkConnectionCopyStatistics(connectionRef);
+       stats_dict = SCNetworkConnectionCopyStatistics(connection);
 
        if (stats_dict) {
                SCPrint(TRUE, stdout, CFSTR("%@\n"), stats_dict);
@@ -356,6 +445,47 @@ nc_statistics(int argc, char **argv)
 
 /* -----------------------------------------------------------------------------
 ----------------------------------------------------------------------------- */
+static void
+checkOnDemandHost(SCDynamicStoreRef store, CFStringRef nodeName, Boolean retry)
+{
+       Boolean                         ok;
+       CFStringRef                     connectionServiceID     = NULL;
+       SCNetworkConnectionStatus       connectionStatus        = 0;
+       CFStringRef                     vpnRemoteAddress        = NULL;
+
+       SCPrint(TRUE, stdout, CFSTR("OnDemand host/domain check (%sretry)\n"), retry ? "" : "no ");
+
+       ok = __SCNetworkConnectionCopyOnDemandInfoWithName(&store,
+                                                          nodeName,
+                                                          retry,
+                                                          &connectionServiceID,
+                                                          &connectionStatus,
+                                                          &vpnRemoteAddress);
+
+       if (ok) {
+               SCPrint(TRUE, stdout, CFSTR("  serviceID      = %@\n"), connectionServiceID);
+               SCPrint(TRUE, stdout, CFSTR("  remote address = %@\n"), vpnRemoteAddress);
+       } else if (SCError() != kSCStatusOK) {
+               SCPrint(TRUE, stdout, CFSTR("%sretry\n"), retry ? "" : "no ");
+               SCPrint(TRUE, stdout,
+                       CFSTR("  Unable to copy OnDemand information for connection: %s\n"),
+                       SCErrorString(SCError()));
+       } else {
+               SCPrint(TRUE, stdout, CFSTR("  no match\n"));
+       }
+
+       if (connectionServiceID != NULL) {
+               CFRelease(connectionServiceID);
+               connectionServiceID = NULL;
+       }
+       if (vpnRemoteAddress != NULL) {
+               CFRelease(vpnRemoteAddress);
+               vpnRemoteAddress = NULL;
+       }
+
+       return;
+}
+
 static void
 nc_ondemand(int argc, char **argv)
 {
@@ -366,16 +496,21 @@ nc_ondemand(int argc, char **argv)
 
        store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL);
        if (store == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("do_nc_ondemand SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
+               SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError()));
                goto done;
        }
 
-       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetOnDemand);
-       if (key == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("do_nc_ondemand SCDynamicStoreKeyCreateNetworkGlobalEntity() failed: %s\n"), SCErrorString(SCError()));
+       if (argc > 0) {
+               CFStringRef     nodeName;
+
+               nodeName = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+               checkOnDemandHost(store, nodeName, FALSE);
+               checkOnDemandHost(store, nodeName, TRUE);
                goto done;
        }
 
+       key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetOnDemand);
+
        ondemand_dict = SCDynamicStoreCopyValue(store, key);
        if (ondemand_dict) {
                SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict);
@@ -391,33 +526,60 @@ done:
        exit(exit_code);
 }
 
+
 /* -----------------------------------------------------------------------------
- Given a string 'key' and a string prefix 'prefix',
- return the next component in the slash '/' separated
- key.  If no slash follows the prefix, return NULL.
+ ----------------------------------------------------------------------------- */
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
 
- Examples:
- 1. key = "a/b/c" prefix = "a/"    returns "b"
- 2. key = "a/b/c" prefix = "a/b/"  returns NULL
------------------------------------------------------------------------------ */
-CFStringRef parse_component(CFStringRef key, CFStringRef prefix)
+CFStringRef
+copy_padded_string(CFStringRef original, int width)
 {
-       CFMutableStringRef      comp;
-       CFRange                 range;
+       CFMutableStringRef      padded;
 
-       if (!CFStringHasPrefix(key, prefix))
-               return NULL;
+       padded = CFStringCreateMutableCopy(NULL, 0, original);
+       CFStringPad(padded, CFSTR(" "), MAX(CFStringGetLength(original), width), 0);
+       return padded;
+}
 
-       comp = CFStringCreateMutableCopy(NULL, 0, key);
-       CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
-       range = CFStringFind(comp, CFSTR("/"), 0);
-       if (range.location == kCFNotFound) {
-               CFRelease(comp);
-               return NULL;
-       }
-       range.length = CFStringGetLength(comp) - range.location;
-       CFStringDelete(comp, range);
-       return comp;
+
+static void
+nc_print_VPN_service(SCNetworkServiceRef service)
+{
+       CFStringRef type = NULL;
+       CFStringRef sub_type = NULL;
+
+       nc_get_service_type_and_subtype(service, &type, &sub_type);
+
+       CFStringRef service_name = SCNetworkServiceGetName(service);
+       if (service_name == NULL)
+               service_name = CFSTR("");
+       CFStringRef service_name_quoted = CFStringCreateWithFormat(NULL, NULL, CFSTR("\"%@\""), service_name);
+       if (service_name_quoted == NULL) {
+               service_name_quoted = CFRetain(CFSTR(""));
+       }
+       CFStringRef service_name_padded = copy_padded_string(service_name, 30);
+
+       CFStringRef service_id   = SCNetworkServiceGetServiceID(service);
+       SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(service);
+       CFStringRef display_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+       if (display_name == NULL)
+               display_name = CFSTR("");
+       CFStringRef display_name_padded = copy_padded_string(display_name, 18);
+
+
+       SCPrint(TRUE,
+               stdout,
+               CFSTR("%@  %@ %@ %@ [%@%@%@]\n"),
+               SCNetworkServiceGetEnabled(service) ? CFSTR("*") : CFSTR(" "),
+               service_id,
+               display_name_padded,
+               service_name_padded,
+               type,
+               (sub_type == NULL) ? CFSTR("") : CFSTR(":"),
+               (sub_type == NULL) ? CFSTR("") : sub_type);
+       CFRelease(service_name_quoted);
+       CFRelease(display_name_padded);
+       CFRelease(service_name_padded);
 }
 
 
@@ -427,208 +589,79 @@ static void
 nc_list(int argc, char **argv)
 {
        int                     count;
-       int                     exit_code       = 1;
        int                     i;
-       CFStringRef             key             = NULL;
-       CFMutableDictionaryRef  names           = NULL;
        CFArrayRef              services        = NULL;
-       CFStringRef             setup           = NULL;
-       SCDynamicStoreRef       store;
 
-       store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL);
-       if (store == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
-               goto done;
-       }
-       key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
-       if (key == NULL ) {
-               SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create key string\n"));
-               goto done;
-       }
-       setup = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/"), kSCDynamicStoreDomainSetup, kSCCompNetwork, kSCCompService);
-       if (setup == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreKeyCreate() failed to create setup string\n"));
-               goto done;
-       }
-       names = CFDictionaryCreateMutable(NULL,
-                                         0,
-                                         &kCFTypeDictionaryKeyCallBacks,
-                                         &kCFTypeDictionaryValueCallBacks);
-       if (names == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("nc_list CFDictionaryCreateMutable() failed to create names dictionary\n"));
-               goto done;
-       }
+       SCPrint(TRUE, stdout, CFSTR("Available network connection services in the current set (*=enabled):\n"));
        services = SCNetworkConnectionCopyAvailableServices(NULL);
        if (services != NULL) {
                count = CFArrayGetCount(services);
 
                for (i = 0; i < count; i++) {
                        SCNetworkServiceRef     service;
-                       CFStringRef             serviceID;
-                       CFStringRef             serviceName;
 
                        service = CFArrayGetValueAtIndex(services, i);
-                       serviceID = SCNetworkServiceGetServiceID(service);
-                       serviceName = SCNetworkServiceGetName(service);
-                       if (serviceName != NULL) {
-                               CFDictionarySetValue(names, serviceID, serviceName);
-                       }
+                       nc_print_VPN_service(service);
                }
 
-               CFRelease(services);
-       }
-
-       services = SCDynamicStoreCopyKeyList(store, key);
-       if (services == NULL ) {
-               SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreCopyKeyList() failed: %s\n"), SCErrorString(SCError()));
-               goto done;
        }
-
-       count = CFArrayGetCount(services);
-       for (i = 0; i < count; i++) {
-               CFStringRef serviceID;
-
-               serviceID = parse_component(CFArrayGetValueAtIndex(services, i), setup);
-               if (serviceID) {
-                       CFStringRef     iftype;
-                       CFStringRef     ifsubtype;
-                       CFStringRef     interface_key   = NULL;
-                       CFDictionaryRef interface_dict  = NULL;
-                       CFStringRef     service_name;
-
-                       interface_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, kSCEntNetInterface);
-                       if (!interface_key)  {
-                               SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreKeyCreateNetworkServiceEntity() failed to interface key string\n"));
-                               goto endloop;
-                       }
-
-                       interface_dict = SCDynamicStoreCopyValue(store, interface_key);
-                       if (!interface_dict) {
-                               SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreCopyValue() to copy interface dictionary: %s\n"), SCErrorString(SCError()));
-                               goto endloop;
-                       }
-
-                       iftype = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceType);
-                       if (!iftype) {
-                               // is that an error condition ???
-                               goto endloop;
-                       }
-
-                       if (!CFEqual(iftype, kSCEntNetPPP) &&
-                               !CFEqual(iftype, kSCEntNetIPSec) &&
-                               !CFEqual(iftype, kSCEntNetVPN))
-                               goto endloop;
-
-                       ifsubtype = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceSubType);
-
-                       service_name = CFDictionaryGetValue(names, serviceID);
-
-                       SCPrint(TRUE, stdout, CFSTR("[%@%@%@] %@%s%@\n"),
-                               iftype ? iftype : CFSTR("?"),
-                               ifsubtype ? CFSTR("/") : CFSTR(""),
-                               ifsubtype ? ifsubtype : CFSTR(""),
-                               serviceID,
-                               service_name ? " : " : "",
-                               service_name ? service_name : CFSTR(""));
-
-                   endloop:
-                       my_CFRelease(&interface_key);
-                       my_CFRelease(&interface_dict);
-                       my_CFRelease(&serviceID);
-               }
-       }
-
-       exit_code = 0;
-done:
        my_CFRelease(&services);
-       my_CFRelease(&names);
-       my_CFRelease(&setup);
-       my_CFRelease(&key);
-       my_CFRelease(&store);
-       exit(exit_code);
+       exit(0);
 }
 
+
 /* -----------------------------------------------------------------------------
 ----------------------------------------------------------------------------- */
 static void
 nc_show(int argc, char **argv)
 {
+       SCNetworkServiceRef     service = NULL;
        SCDynamicStoreRef       store = NULL;
        int                     exit_code = 1;
-       CFStringRef             setup = NULL;
-       CFStringRef             serviceIDRef = NULL;
-       CFArrayRef              services = NULL;
+       CFStringRef             serviceID = NULL;
        CFStringRef             iftype = NULL;
        CFStringRef             ifsubtype = NULL;
-       CFStringRef             interface_key = NULL;
-       CFDictionaryRef         interface_dict = NULL;
        CFStringRef             type_entity_key = NULL;
        CFStringRef             subtype_entity_key = NULL;
        CFDictionaryRef         type_entity_dict = NULL;
        CFDictionaryRef         subtype_entity_dict = NULL;
 
-       serviceIDRef = nc_copy_serviceID(argc, argv);
-       if (serviceIDRef == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("No service ID\n"));
-               goto done;
-       }
-
-       store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL);
-       if (store == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("nc_show SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError()));
-               goto done;
+       service = nc_copy_service_from_arguments(argc, argv, NULL);
+       if (service == NULL) {
+               SCPrint(TRUE, stderr, CFSTR("No service\n"));
+               exit(exit_code);
        }
 
-       interface_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceIDRef, kSCEntNetInterface);
-       if (!interface_key) {
-               SCPrint(TRUE, stderr, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create interface key\n"));
-               goto done;
-       }
+       serviceID = SCNetworkServiceGetServiceID(service);
 
-       interface_dict = SCDynamicStoreCopyValue(store, interface_key);
-       if (!interface_dict) {
-               SCPrint(TRUE, stdout, CFSTR("Interface dictionary missing for service ID : %@\n"), serviceIDRef);
-               goto done;
-       }
-
-       iftype = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceType);
-       if (!iftype) {
-               SCPrint(TRUE, stdout, CFSTR("Interface Type missing for service ID : %@\n"), serviceIDRef);
-               goto done;
-       }
+       nc_get_service_type_and_subtype(service, &iftype, &ifsubtype);
 
        if (!CFEqual(iftype, kSCEntNetPPP) &&
-               !CFEqual(iftype, kSCEntNetIPSec) &&
-               !CFEqual(iftype, kSCEntNetVPN)) {
-               SCPrint(TRUE, stdout, CFSTR("Interface Type [%@] invalid for service ID : %@\n"), iftype, serviceIDRef);
+           !CFEqual(iftype, kSCEntNetIPSec) &&
+           !CFEqual(iftype, kSCEntNetVPN)) {
+               SCPrint(TRUE, stderr, CFSTR("Not a connection oriented service: %@\n"), serviceID);
                goto done;
        }
 
-       ifsubtype = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceSubType);
-       SCPrint(TRUE, stdout, CFSTR("[%@%@%@] %@\n"),
-               iftype ? iftype : CFSTR("?"),
-               ifsubtype ? CFSTR("/") : CFSTR(""),
-               ifsubtype ? ifsubtype : CFSTR(""),
-               serviceIDRef);
+       type_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, iftype);
+
+       nc_print_VPN_service(service);
 
-       type_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceIDRef, iftype);
-       if (!type_entity_key) {
-               SCPrint(TRUE, stderr, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create type entity key\n"));
+       store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL);
+       if (store == NULL) {
+               SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError()));
                goto done;
        }
        type_entity_dict = SCDynamicStoreCopyValue(store, type_entity_key);
+
        if (!type_entity_dict) {
-               SCPrint(TRUE, stdout, CFSTR("%@ dictionary missing for service ID : %@\n"), iftype, serviceIDRef);
+               SCPrint(TRUE, stderr, CFSTR("No \"%@\" configuration available\n"), iftype);
        } else {
                SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), iftype, type_entity_dict);
        }
 
        if (ifsubtype) {
-               subtype_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceIDRef, ifsubtype);
-               if (!subtype_entity_key) {
-                       SCPrint(TRUE, stderr, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create subtype entity key\n"));
-                       goto done;
-               }
+               subtype_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, ifsubtype);
                subtype_entity_dict = SCDynamicStoreCopyValue(store, subtype_entity_key);
                if (!subtype_entity_dict) {
                        //
@@ -641,17 +674,12 @@ nc_show(int argc, char **argv)
        exit_code = 0;
 
 done:
-       my_CFRelease(&serviceIDRef);
-       my_CFRelease(&interface_key);
-       my_CFRelease(&interface_dict);
        my_CFRelease(&type_entity_key);
        my_CFRelease(&type_entity_dict);
        my_CFRelease(&subtype_entity_key);
        my_CFRelease(&subtype_entity_dict);
-       my_CFRelease(&services);
-       my_CFRelease(&setup);
        my_CFRelease(&store);
-
+       my_CFRelease(&service);
        exit(exit_code);
 }
 
@@ -663,40 +691,33 @@ nc_select(int argc, char **argv)
        SCNetworkSetRef         current_set;
        int                     exit_code       = 1;
        SCNetworkServiceRef     service         = NULL;
-       CFStringRef             service_id;
        Boolean                 status;
 
-       service_id = nc_copy_serviceID(argc, argv);
-       if (service_id == NULL) {
-               SCPrint(TRUE, stderr, CFSTR("No service identifier\n"));
-               exit(exit_code);
-       }
-
        do_prefs_init();        /* initialization */
        do_prefs_open(0, NULL); /* open default prefs */
 
        current_set = SCNetworkSetCopyCurrent(prefs);
        if (current_set == NULL) {
-               SCPrint(TRUE, stdout, CFSTR("nc_select SCNetworkSetCopyCurrent() failed: %s\n"), SCErrorString(SCError()));
+               SCPrint(TRUE, stderr, CFSTR("No current location\n"), SCErrorString(SCError()));
                goto done;
        }
 
-       service = nc_copy_service(current_set, service_id);
+       service = nc_copy_service_from_arguments(argc, argv, current_set);
        if (service == NULL) {
-               SCPrint(TRUE, stdout, CFSTR("No service\n"));
+               SCPrint(TRUE, stderr, CFSTR("No service\n"));
                goto done;
        }
 
 #if !TARGET_OS_IPHONE
        status = SCNetworkServiceSetEnabled(service, TRUE);
        if (!status) {
-               SCPrint(TRUE, stdout, CFSTR("nc_select SCNetworkServiceSetEnabled() failed: %s\n"), SCErrorString(SCError()));
+               SCPrint(TRUE, stderr, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError()));
                goto done;
        }
 #else
        status = SCNetworkSetSetSelectedVPNService(current_set, service);
        if (!status) {
-               SCPrint(TRUE, stdout, CFSTR("nc_select SCNetworkSetSetSelectedVPNService() failed: %s\n"), SCErrorString(SCError()));
+               SCPrint(TRUE, stderr, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError()));
                goto done;
        }
 #endif
@@ -704,8 +725,7 @@ nc_select(int argc, char **argv)
        _prefs_save();
        exit_code = 0;
 done:
-
-       my_CFRelease(&service_id);
+       my_CFRelease(&service);
        my_CFRelease(&current_set);
        _prefs_close();
        exit(exit_code);
index 05413241831c3ca3896b29f63b58c9a2877df011..817bbee4f9aae0425593f9f18431edeecf705ef1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -24,7 +24,7 @@
 /*
  * Modification History
  *
- * March1, 2010                        Christophe Allie <callie@apple.com>
+ * March 1, 2010                       Christophe Allie <callie@apple.com>
  * - initial revision
  */
 
@@ -34,6 +34,9 @@
 #include <sys/cdefs.h>
 #include <SystemConfiguration/SystemConfiguration.h>
 
+extern CFStringRef             username;
+extern CFStringRef             password;
+extern CFStringRef             sharedsecret;
 
 __BEGIN_DECLS
 
index 550032de147915940b88f18920ba171e0bca6c07..cb1ebfbdbbef8454d4af664a2be7949aba4ccae4 100644 (file)
@@ -61,7 +61,7 @@ __private_extern__ CFNumberRef                        CFNumberRef_1   = NULL;
 
 
 __private_extern__
-CFNumberRef
+CF_RETURNS_RETAINED CFNumberRef
 _copy_number(const char *arg)
 {
        int     val;
@@ -883,6 +883,7 @@ do_net_update(int argc, char **argv)
 
                                n = CFArrayGetCount(sets);
                                CFRelease(sets);
+                               sets = NULL;
                                if (n > 0) {
                                        SCPrint(TRUE, stdout, CFSTR("no current set\n"));
                                        return;
index 05bbb8e8e931ed727542bdd02252b7bae0261335..bd57435e80fa7ac999ae165e791a49c54cce47ab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004, 2006, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -96,6 +96,7 @@ Boolean               _process_options(optionsRef             options,
                                 char                   **argv,
                                 CFMutableDictionaryRef newConfiguration);
 
+CF_RETURNS_RETAINED
 CFNumberRef    _copy_number    (const char *arg);
 
 CFIndex                _find_option    (const char     *option,
@@ -108,24 +109,24 @@ CFIndex           _find_selection (CFStringRef    choice,
 
 void           _show_entity    (CFDictionaryRef entity, CFStringRef prefix);
 
-void   do_net_init             (void);
-void   do_net_quit             (int argc, char **argv);
+void           do_net_init     (void);
+void           do_net_quit     (int argc, char **argv);
 
-void   do_net_open             (int argc, char **argv);
-void   do_net_commit           (int argc, char **argv);
-void   do_net_apply            (int argc, char **argv);
-void   do_net_close            (int argc, char **argv);
+void           do_net_open     (int argc, char **argv);
+void           do_net_commit   (int argc, char **argv);
+void           do_net_apply    (int argc, char **argv);
+void           do_net_close    (int argc, char **argv);
 
-void   do_net_create           (int argc, char **argv);
-void   do_net_disable          (int argc, char **argv);
-void   do_net_enable           (int argc, char **argv);
-void   do_net_remove           (int argc, char **argv);
-void   do_net_select           (int argc, char **argv);
-void   do_net_set              (int argc, char **argv);
-void   do_net_show             (int argc, char **argv);
-void   do_net_update           (int argc, char **argv);
+void           do_net_create   (int argc, char **argv);
+void           do_net_disable  (int argc, char **argv);
+void           do_net_enable   (int argc, char **argv);
+void           do_net_remove   (int argc, char **argv);
+void           do_net_select   (int argc, char **argv);
+void           do_net_set      (int argc, char **argv);
+void           do_net_show     (int argc, char **argv);
+void           do_net_update   (int argc, char **argv);
 
-void   do_net_snapshot         (int argc, char **argv);
+void           do_net_snapshot (int argc, char **argv);
 
 __END_DECLS
 
index 4303b33f56704f5cdd458f19cba2ef5a0410bfcb..ba122042e16a110e3da0505014fae73e9c1458cf 100644 (file)
@@ -29,6 +29,7 @@
  */
 
 
+#include <TargetConditionals.h>
 #include "scutil.h"
 #include "net.h"
 #include "prefs.h"
 #include <SystemConfiguration/LinkConfiguration.h>
 
 
+#if    TARGET_OS_EMBEDDED
+#define        INLINE_PASSWORDS_USE_CFSTRING
+#endif // TARGET_OS_EMBEDDED
+
+
 #pragma mark -
 #pragma mark Interface management
 
@@ -119,6 +125,7 @@ _find_interface(int argc, char **argv, int *nArgs)
                goto done;
        }
 
+#if    !TARGET_OS_IPHONE
        else if (strcasecmp(argv[0], "$bond") == 0) {
                CFStringRef     interfaceType;
 
@@ -148,6 +155,7 @@ _find_interface(int argc, char **argv, int *nArgs)
                }
                allowIndex = FALSE;
        }
+#endif // !TARGET_OS_IPHONE
 
        else if (strcasecmp(argv[0], "$bridge") == 0) {
                CFStringRef     interfaceType;
@@ -924,6 +932,63 @@ show_interfaces(int argc, char **argv)
 /* -------------------- */
 
 
+static int
+__doRank(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+       SCNetworkInterfaceRef           interface;
+       CFStringRef                     interfaceName;
+       Boolean                         ok      = FALSE;
+       SCNetworkServicePrimaryRank     rank    = kSCNetworkServicePrimaryRankDefault;
+       SCDynamicStoreRef               store;
+
+       if (argc < 1) {
+               SCPrint(TRUE, stdout,
+                       CFSTR("%s not specified\n"),
+                       description != NULL ? description : "rank");
+               return -1;
+       }
+
+       if (strlen(argv[0]) == 0) {
+               rank = kSCNetworkServicePrimaryRankDefault;
+       } else if ((strcasecmp(argv[0], "First") == 0)) {
+               rank = kSCNetworkServicePrimaryRankFirst;
+       } else if ((strcasecmp(argv[0], "Last") == 0)) {
+               rank = kSCNetworkServicePrimaryRankLast;
+       } else if ((strcasecmp(argv[0], "Never") == 0)) {
+               rank = kSCNetworkServicePrimaryRankNever;
+       } else {
+               SCPrint(TRUE, stdout, CFSTR("invalid rank\n"));
+               return -1;
+       }
+
+       interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
+       if (interfaceName == NULL) {
+               SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
+               return FALSE;
+       }
+
+       store = SCDynamicStoreCreate(NULL, CFSTR("scutil --net"), NULL, NULL);
+       interface = _SCNetworkInterfaceCopyActive(store, interfaceName);
+       CFRelease(store);
+       if (interface == NULL) {
+               SCPrint(TRUE, stdout, CFSTR("No active interface\n"));
+               return -1;
+       }
+
+       ok = SCNetworkInterfaceSetPrimaryRank(interface, rank);
+       CFRelease(interface);
+       if (!ok) {
+               SCPrint(TRUE, stdout, CFSTR("could not update per-interface rank\n"));
+               return -1;
+       }
+
+       return 1;
+}
+
+
+/* -------------------- */
+
+
 static void
 _replaceOne(const void *key, const void *value, void *context)
 {
@@ -1041,7 +1106,9 @@ static options airportOptions[] = {
        { "media"     , NULL, isString     , &kSCPropNetEthernetMediaSubType, NULL, NULL },
        { "mediaopt"  , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
 
-       { "?"         , NULL , isHelp     , NULL                            , NULL,
+       { "rank"      , NULL, isOther      , NULL                            , __doRank, NULL },
+
+       { "?"         , NULL, isHelp       , NULL                            , NULL,
            "\nAirPort configuration commands\n\n"
            " set interface [mtu n] [media type] [mediaopts opts]\n"
        }
@@ -1131,7 +1198,9 @@ static options ethernetOptions[] = {
        { "tso"       , NULL, isOther      , &kSCPropNetEthernetCapabilityTSO   , __doCapability, NULL },
        { "txcsum"    , NULL, isOther      , &kSCPropNetEthernetCapabilityTXCSUM, __doCapability, NULL },
 
-       { "?"         , NULL , isHelp     , NULL                            , NULL,
+       { "rank"      , NULL, isOther      , NULL                            , __doRank, NULL },
+
+       { "?"         , NULL, isHelp       , NULL                            , NULL,
            "\nEthernet configuration commands\n\n"
            " set interface [mtu n] [media type] [mediaopts opts]\n"
        }
@@ -1180,6 +1249,11 @@ __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int
        encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecSharedSecretEncryption);
        if (strlen(argv[0]) > 0) {
                if (encryptionType == NULL) {
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+                       CFStringRef             pw;
+
+                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else  // INLINE_PASSWORDS_USE_CFSTRING
                        CFIndex                 n;
                        CFMutableDataRef        pw;
                        CFStringRef             str;
@@ -1188,10 +1262,12 @@ __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int
                        n = CFStringGetLength(str);
                        pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
                        CFDataSetLength(pw, n * sizeof(UniChar));
+                       /* ALIGN: CF aligns to at least >8 bytes */
                        CFStringGetCharacters(str,
                                              CFRangeMake(0, n),
-                                             (UniChar *)CFDataGetMutableBytePtr(pw));
+                                             (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
                        CFRelease(str);
+#endif // INLINE_PASSWORDS_USE_CFSTRING
 
                        CFDictionarySetValue(newConfiguration, key, pw);
                        CFRelease(pw);
@@ -1277,6 +1353,11 @@ __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int
        encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecXAuthPasswordEncryption);
        if (strlen(argv[0]) > 0) {
                if (encryptionType == NULL) {
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+                       CFStringRef             pw;
+
+                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else  // INLINE_PASSWORDS_USE_CFSTRING
                        CFIndex                 n;
                        CFMutableDataRef        pw;
                        CFStringRef             str;
@@ -1285,10 +1366,12 @@ __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int
                        n = CFStringGetLength(str);
                        pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
                        CFDataSetLength(pw, n * sizeof(UniChar));
+                       /* ALIGN: CF aligns to at least >8 byte boundries */
                        CFStringGetCharacters(str,
                                              CFRangeMake(0, n),
-                                             (UniChar *)CFDataGetMutableBytePtr(pw));
+                                             (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
                        CFRelease(str);
+#endif // INLINE_PASSWORDS_USE_CFSTRING
 
                        CFDictionarySetValue(newConfiguration, key, pw);
                        CFRelease(pw);
@@ -1362,7 +1445,7 @@ __doIPSecXAuthPasswordType(CFStringRef key, const char *description, void *info,
 }
 
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 __cleanupDomainName(CFStringRef domain)
 {
        CFMutableStringRef      newDomain;
@@ -1642,6 +1725,11 @@ __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, ch
        encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption);
        if (strlen(argv[0]) > 0) {
                if (encryptionType == NULL) {
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+                       CFStringRef             pw;
+
+                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else  // INLINE_PASSWORDS_USE_CFSTRING
                        CFIndex                 n;
                        CFMutableDataRef        pw;
                        CFStringRef             str;
@@ -1650,10 +1738,12 @@ __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, ch
                        n = CFStringGetLength(str);
                        pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
                        CFDataSetLength(pw, n * sizeof(UniChar));
+                       /* ALIGN: CF aligns to at least >8 byte boundries */
                        CFStringGetCharacters(str,
                                              CFRangeMake(0, n),
-                                             (UniChar *)CFDataGetMutableBytePtr(pw));
+                                             (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
                        CFRelease(str);
+#endif // INLINE_PASSWORDS_USE_CFSTRING
 
                        CFDictionarySetValue(newConfiguration, key, pw);
                        CFRelease(pw);
@@ -1992,7 +2082,11 @@ __doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, ch
        encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetVPNAuthPasswordEncryption);
        if (strlen(argv[0]) > 0) {
                if (encryptionType == NULL) {
-#ifdef USE_INLINE_CFDATA
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+                       CFStringRef             pw;
+
+                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else  // INLINE_PASSWORDS_USE_CFSTRING
                        CFIndex                 n;
                        CFMutableDataRef        pw;
                        CFStringRef             str;
@@ -2003,13 +2097,9 @@ __doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, ch
                        CFDataSetLength(pw, n * sizeof(UniChar));
                        CFStringGetCharacters(str,
                                              CFRangeMake(0, n),
-                                             (UniChar *)CFDataGetMutableBytePtr(pw));
+                                             (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
                        CFRelease(str);
-#else  // USE_INLINE_CFDATA
-                       CFStringRef             pw;
-
-                       pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
-#endif // USE_INLINE_CFDATA
+#endif // INLINE_PASSWORDS_USE_CFSTRING
 
                        CFDictionarySetValue(newConfiguration, key, pw);
                        CFRelease(pw);
@@ -2251,7 +2341,7 @@ show_interface(int argc, char **argv)
 
 
 __private_extern__
-CFStringRef
+CF_RETURNS_RETAINED CFStringRef
 _interface_description(SCNetworkInterfaceRef interface)
 {
        CFMutableStringRef      description;
index af429567046be1cbe2d29d19ab8419f7f1bca5c4..4d1ed4a0160a4666426b30502520237b921f1c46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 __BEGIN_DECLS
 
+CF_RETURNS_RETAINED
 CFStringRef            _interface_description  (SCNetworkInterfaceRef interface);
+
 SCNetworkInterfaceRef  _find_interface         (int argc, char **argv, int *nArgs);
 
-void   create_interface        (int argc, char **argv);
-void   select_interface        (int argc, char **argv);
-void   set_interface           (int argc, char **argv);
-void   show_interface          (int argc, char **argv);
-void   show_interfaces         (int argc, char **argv);
+void                   create_interface        (int argc, char **argv);
+void                   select_interface        (int argc, char **argv);
+void                   set_interface           (int argc, char **argv);
+void                   show_interface          (int argc, char **argv);
+void                   show_interfaces         (int argc, char **argv);
 
 __END_DECLS
 
index 2da53af8c11ea956bf7172806c3911c7af94e514..46869de52e5ffce252f3728c0f8d4a659a0054e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2009, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -66,10 +66,7 @@ __copyIPv4Address(const char *arg)
        char                    buf[128];
        struct sockaddr_in      sin;
 
-       bzero(&sin, sizeof(sin));
-       sin.sin_len    = sizeof(sin);
-       sin.sin_family = AF_INET;
-       if (inet_aton(arg, &sin.sin_addr) != 1) {
+       if (_SC_string_to_sockaddr(arg, AF_INET, (void *)&sin, sizeof(sin)) == NULL) {
                return NULL;
        }
 
@@ -82,21 +79,12 @@ static CFStringRef
 __copyIPv6Address(const char *arg)
 {
        char                    buf[128];
-       char                    *p;
        struct sockaddr_in6     sin6;
 
-       bzero(&sin6, sizeof(sin6));
-       sin6.sin6_len    = sizeof(sin6);
-       sin6.sin6_family = AF_INET6;
-       if (inet_pton(AF_INET6, arg, &sin6.sin6_addr) != 1) {
+       if (_SC_string_to_sockaddr(arg, AF_INET6, (void *)&sin6, sizeof(sin6)) == NULL) {
                return NULL;
        }
 
-       p = strchr(arg, '%');
-       if (p != NULL) {
-               sin6.sin6_scope_id = if_nametoindex(p + 1);
-       }
-
        _SC_sockaddr_to_string((struct sockaddr *)&sin6, buf, sizeof(buf));
        return CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
 }
@@ -421,7 +409,7 @@ select_protocol(int argc, char **argv)
 #pragma mark DNS
 
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 __cleanupDomainName(CFStringRef domain)
 {
        CFMutableStringRef      newDomain;
@@ -1173,6 +1161,7 @@ __doProxyPort(CFStringRef key, const char *description, void *info, int argc, ch
                    !CFNumberGetValue(num, kCFNumberIntType, &port) ||
                    (port < 0) || (port > 65535)) {
                        SCPrint(TRUE, stdout, CFSTR("invalid %s proxy port number\n"), currentProxy->proxy);
+                       if (num != NULL) CFRelease(num);
                        return -1;
                }
 
@@ -1257,7 +1246,7 @@ set_protocol_proxies(int argc, char **argv, CFMutableDictionaryRef newConfigurat
 #if    !TARGET_OS_IPHONE
 
 
-static CFStringRef
+static CF_RETURNS_RETAINED CFStringRef
 __cleanupName(CFStringRef name)
 {
        CFMutableStringRef      newName;
@@ -1628,7 +1617,7 @@ show_protocols(int argc, char **argv)
 
 
 __private_extern__
-CFStringRef
+CF_RETURNS_RETAINED CFStringRef
 _protocol_description(SCNetworkProtocolRef protocol, Boolean skipEmpty)
 {
        CFDictionaryRef         configuration;
index 30b650efc65e5f0d46d99635104d4e08a438f5a7..976cf1114c6c096dc2be53ab357121ffe5031931 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004, 2011 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 __BEGIN_DECLS
 
 CFComparisonResult     _compare_protocols      (const void *val1, const void *val2, void *context);
+
+CF_RETURNS_RETAINED
 CFStringRef            _protocol_description   (SCNetworkProtocolRef protocol, Boolean skipEmpty);
 
-void   create_protocol         (int argc, char **argv);
-void   disable_protocol        (int argc, char **argv);
-void   enable_protocol         (int argc, char **argv);
-void   remove_protocol         (int argc, char **argv);
-void   select_protocol         (int argc, char **argv);
-void   set_protocol            (int argc, char **argv);
-void   show_protocol           (int argc, char **argv);
-void   show_protocols          (int argc, char **argv);
+void                   create_protocol         (int argc, char **argv);
+void                   disable_protocol        (int argc, char **argv);
+void                   enable_protocol         (int argc, char **argv);
+void                   remove_protocol         (int argc, char **argv);
+void                   select_protocol         (int argc, char **argv);
+void                   set_protocol            (int argc, char **argv);
+void                   show_protocol           (int argc, char **argv);
+void                   show_protocols          (int argc, char **argv);
 
 __END_DECLS
 
index aadfbe0ad0800c1e0c9a90359caccc8c2a91c0d9..a50302e85917c85c42d2d3c956d7ae7fcbdc12dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2008-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2008-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -34,6 +34,7 @@
 #include <pthread.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/time.h>
 #include <sys/un.h>
 #include <unistd.h>
 
@@ -45,6 +46,39 @@ static int                   osig;
 static struct sigaction                *oact   = NULL;
 
 
+static char *
+elapsed()
+{
+       int                     n;
+       static char             str[128];
+       struct tm               tm_diff;
+       struct tm               tm_now;
+       struct timeval          tv_diff;
+       struct timeval          tv_now;
+       static struct timeval   tv_then = { 0, 0 };
+
+       (void)gettimeofday(&tv_now, NULL);
+
+       (void)localtime_r(&tv_now.tv_sec, &tm_now);
+
+       timersub(&tv_now, &tv_then, &tv_diff);
+       (void)localtime_r(&tv_diff.tv_sec, &tm_diff);
+       n = snprintf(str, sizeof(str), "%2d:%02d:%02d.%03d",
+                    tm_now.tm_hour,
+                    tm_now.tm_min,
+                    tm_now.tm_sec,
+                    tv_now.tv_usec / 1000);
+       if (((tv_then.tv_sec != 0) || (tv_then.tv_usec != 0)) && (n < sizeof(str))) {
+               snprintf(&str[n], sizeof(str) - n, " (+%ld.%03d)",
+                        tv_diff.tv_sec,
+                        tv_diff.tv_usec / 1000);
+       }
+
+       tv_then = tv_now;
+       return str;
+}
+
+
 static CFComparisonResult
 sort_keys(const void *p1, const void *p2, void *context) {
        CFStringRef key1 = (CFStringRef)p1;
@@ -67,7 +101,8 @@ storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
                for (i = 0; i < n; i++) {
                        SCPrint(TRUE,
                                stdout,
-                               CFSTR("  changed key [%d] = %@\n"),
+                               CFSTR("  %s changedKey [%d] = %@\n"),
+                               elapsed(),
                                i,
                                CFArrayGetValueAtIndex(changedKeys, i));
                }
@@ -227,7 +262,8 @@ do_notify_changes(int argc, char **argv)
                for (i = 0; i < listCnt; i++) {
                        SCPrint(TRUE,
                                stdout,
-                               CFSTR("  changedKey [%d] = %@\n"),
+                               CFSTR("  %s changedKey [%d] = %@\n"),
+                               elapsed(),
                                i,
                                CFArrayGetValueAtIndex(list, i));
                }
@@ -308,77 +344,6 @@ do_notify_wait(int argc, char **argv)
 }
 
 
-static boolean_t
-notificationWatcher(SCDynamicStoreRef store, void *arg)
-{
-       SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store);
-       SCPrint(TRUE, stdout, CFSTR("  arg = %s.\n"), (char *)arg);
-       return TRUE;
-}
-
-
-static boolean_t
-notificationWatcherVerbose(SCDynamicStoreRef store, void *arg)
-{
-       SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store);
-       SCPrint(TRUE, stdout, CFSTR("  arg = %s.\n"), (char *)arg);
-       do_notify_changes(0, NULL);     /* report the keys that changed */
-       return TRUE;
-}
-
-
-static void *
-_callback(void *arg)
-{
-       SCDynamicStoreCallBack_v1       func  = (SCDynamicStoreCallBack_v1)arg;
-
-       notifyRl = CFRunLoopGetCurrent();
-       if (notifyRl == NULL) {
-               SCPrint(TRUE, stdout, CFSTR("  CFRunLoopGetCurrent() failed\n"));
-               return NULL;
-       }
-
-       if (!SCDynamicStoreNotifyCallback(store, notifyRl, func, "Changed detected by callback handler!")) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
-               notifyRl = NULL;
-               return NULL;
-       }
-
-       pthread_setname_np("n.callback");
-       CFRunLoopRun();
-       notifyRl = NULL;
-       return NULL;
-}
-
-
-__private_extern__
-void
-do_notify_callback(int argc, char **argv)
-{
-       SCDynamicStoreCallBack_v1       func  = notificationWatcher;
-       pthread_attr_t                  tattr;
-       pthread_t                       tid;
-
-       if (notifyRl != NULL) {
-               SCPrint(TRUE, stdout, CFSTR("already active\n"));
-               return;
-       }
-
-       if ((argc == 1) && (strcmp(argv[0], "verbose") == 0)) {
-               func = notificationWatcherVerbose;
-       }
-
-       pthread_attr_init(&tattr);
-       pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
-       pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-//      pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
-       pthread_create(&tid, &tattr, _callback, (void *)func);
-       pthread_attr_destroy(&tattr);
-
-       return;
-}
-
-
 __private_extern__
 void
 do_notify_file(int argc, char **argv)
index ec73edf534515f5a3c888d2ad52d39279e4002dd..27a9f39dee8248df0eadb43825eedad0a88fda2e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -48,7 +48,6 @@ void  do_notify_remove        (int argc, char **argv);
 void   do_notify_changes       (int argc, char **argv);
 void   do_notify_watch         (int argc, char **argv);
 void   do_notify_wait          (int argc, char **argv);
-void   do_notify_callback      (int argc, char **argv);
 void   do_notify_signal        (int argc, char **argv);
 void   do_notify_file          (int argc, char **argv);
 void   do_notify_cancel        (int argc, char **argv);
index 4e201e14981befdd2191d8b282a916089824c635..34e534d5a7990b0618d31b53a96a754172950817 100644 (file)
@@ -52,7 +52,7 @@ static void *
 __loadSecurity(void) {
        static void *image = NULL;
        if (NULL == image) {
-               const char      *framework              = "/System/Library/Frameworks/Security.framework/Versions/A/Security";
+               const char      *framework              = "/System/Library/Frameworks/Security.framework/Security";
                struct stat     statbuf;
                const char      *suffix                 = getenv("DYLD_IMAGE_SUFFIX");
                char            path[MAXPATHLEN];
@@ -145,6 +145,8 @@ _prefs_open(CFStringRef name, CFStringRef prefsID)
 
 #if    !TARGET_OS_IPHONE
                authorization = _createAuthorization();
+#else
+               authorization = (AuthorizationRef)kSCPreferencesUseEntitlementAuthorization;
 #endif /* !TARGET_OS_IPHONE */
        }
 
index c506724c7453e6e546ce23688ba035346392bcf1..7578f44cc43975e4593701e3994251fb2259cad9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -97,11 +97,16 @@ static const struct option longopts[] = {
        { "dns",                no_argument,            NULL,   0       },
        { "get",                required_argument,      NULL,   0       },
        { "help",               no_argument,            NULL,   '?'     },
+       { "nc",                 required_argument,      NULL,   0       },
        { "net",                no_argument,            NULL,   0       },
+       { "nwi",                no_argument,            NULL,   0       },
        { "prefs",              no_argument,            NULL,   0       },
        { "proxy",              no_argument,            NULL,   0       },
        { "set",                required_argument,      NULL,   0       },
-       { "nc",                 required_argument,      NULL,   0       },
+       { "snapshot",           no_argument,            NULL,   0       },
+       { "user",               required_argument,      NULL,   0       },
+       { "password",           required_argument,      NULL,   0       },
+       { "secret",             required_argument,      NULL,   0       },
        { NULL,                 0,                      NULL,   0       }
 };
 
@@ -299,6 +304,9 @@ usage(const char *command)
        SCPrint(TRUE, stderr, CFSTR("\n"));
        SCPrint(TRUE, stderr, CFSTR("   or: %s --proxy\n"), command);
        SCPrint(TRUE, stderr, CFSTR("\tshow \"proxy\" configuration.\n"));
+       SCPrint(TRUE, stderr, CFSTR("\n"));
+       SCPrint(TRUE, stderr, CFSTR("   or: %s --nwi\n"), command);
+       SCPrint(TRUE, stderr, CFSTR("\tshow network information\n"));
 
        if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
                SCPrint(TRUE, stderr, CFSTR("\n"));
@@ -322,9 +330,11 @@ main(int argc, char * const argv[])
 {
        Boolean                 doDNS   = FALSE;
        Boolean                 doNet   = FALSE;
+       Boolean                 doNWI   = FALSE;
        Boolean                 doPrefs = FALSE;
        Boolean                 doProxy = FALSE;
        Boolean                 doReach = FALSE;
+       Boolean                 doSnap  = FALSE;
        char                    *get    = NULL;
        extern int              optind;
        int                     opt;
@@ -377,9 +387,15 @@ main(int argc, char * const argv[])
                        } else if (strcmp(longopts[opti].name, "get") == 0) {
                                get = optarg;
                                xStore++;
+                       } else if (strcmp(longopts[opti].name, "nc") == 0) {
+                               nc_cmd = optarg;
+                               xStore++;
                        } else if (strcmp(longopts[opti].name, "net") == 0) {
                                doNet = TRUE;
                                xStore++;
+                       } else if (strcmp(longopts[opti].name, "nwi") == 0) {
+                               doNWI = TRUE;
+                               xStore++;
                        } else if (strcmp(longopts[opti].name, "prefs") == 0) {
                                doPrefs = TRUE;
                                xStore++;
@@ -389,9 +405,15 @@ main(int argc, char * const argv[])
                        } else if (strcmp(longopts[opti].name, "set") == 0) {
                                set = optarg;
                                xStore++;
-                       } else if (strcmp(longopts[opti].name, "nc") == 0) {
-                               nc_cmd = optarg;
+                       } else if (strcmp(longopts[opti].name, "snapshot") == 0) {
+                               doSnap = TRUE;
                                xStore++;
+                       } else if (strcmp(longopts[opti].name, "user") == 0) {
+                               username = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+                       } else if (strcmp(longopts[opti].name, "password") == 0) {
+                               password = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+                       } else if (strcmp(longopts[opti].name, "secret") == 0) {
+                               sharedsecret = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
                        }
                        break;
                case '?':
@@ -430,6 +452,21 @@ main(int argc, char * const argv[])
                /* NOT REACHED */
        }
 
+       if (doNWI) {
+               do_nwi(argc, (char**)argv);
+               /* NOT REACHED */
+       }
+
+       if (doSnap) {
+               if (!enablePrivateAPI || (geteuid() != 0)) {
+                       usage(prog);
+               }
+
+               do_open(0, NULL);       /* open the dynamic store */
+               do_snapshot(argc, (char**)argv);
+               exit(0);
+       }
+
        /* are we looking up a preference value */
        if (get) {
                if (findPref(get) < 0) {
index 6f00f3857468348afd93f162580d5ffed57a5952..ed31af137ae53ff88c786c8f6fac0fae9afa0e45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2004, 2010, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -32,6 +32,7 @@
  */
 
 #include "scutil.h"
+#include "cache.h"
 #include "session.h"
 #include "notifications.h"
 
@@ -81,6 +82,8 @@ do_open(int argc, char **argv)
        watchedKeys     = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
        watchedPatterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
 
+       cache_close();
+
        return;
 }
 
@@ -112,27 +115,8 @@ do_close(int argc, char **argv)
                CFRelease(watchedPatterns);
                watchedPatterns = NULL;
        }
-       return;
-}
 
+       cache_close();
 
-__private_extern__
-void
-do_lock(int argc, char **argv)
-{
-       if (!SCDynamicStoreLock(store)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
-       }
-       return;
-}
-
-
-__private_extern__
-void
-do_unlock(int argc, char **argv)
-{
-       if (!SCDynamicStoreUnlock(store)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
-       }
        return;
 }
index b26bf4b6f783392d5eb8e49e6f868680858a5b54..6c11ffa60437b38aee4b9d34ff7af917f8e58d2f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -37,8 +37,6 @@ __BEGIN_DECLS
 
 void   do_open                 (int argc, char **argv);
 void   do_close                (int argc, char **argv);
-void   do_lock                 (int argc, char **argv);
-void   do_unlock               (int argc, char **argv);
 
 __END_DECLS
 
index 471ac4c67cadfd683b03cde4e7f8c517054e7036..bc9160eb2502c3e8e7fbde9a0311e2fb98e08ff1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2005, 2007-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2007-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <arpa/inet.h>
 
 #include <dnsinfo.h>
+#include <network_information.h>
+#include "SCNetworkReachabilityInternal.h"
+
+static Boolean resolver_bypass;
+
+static CF_RETURNS_RETAINED CFMutableDictionaryRef
+_setupReachabilityOptions(int argc, char **argv, const char *interface)
+{
+       CFMutableDictionaryRef  options;
+
+       options = CFDictionaryCreateMutable(NULL,
+                                           0,
+                                           &kCFTypeDictionaryKeyCallBacks,
+                                           &kCFTypeDictionaryValueCallBacks);
+
+       if (argc > 2) {
+               struct addrinfo         hints   = { 0 };
+               int                     n_hints = 0;
+               int                     i;
+
+               for (i = 2; i < argc; i++) {
+                       if (strcasecmp(argv[i], "interface") == 0) {
+                               if (++i >= argc) {
+                                       SCPrint(TRUE, stderr, CFSTR("No interface\n"));
+                                       CFRelease(options);
+                                       exit(1);
+                               }
+
+                               interface = argv[i];
+                               continue;
+                       }
+
+
+                       if (strcasecmp(argv[i], "llq") == 0) {
+                               CFDictionarySetValue(options,
+                                                    kSCNetworkReachabilityOptionLongLivedQueryBypass,
+                                                    kCFBooleanFalse);
+                               continue;
+                       } else if (strcasecmp(argv[i], "no-llq") == 0) {
+                               CFDictionarySetValue(options,
+                                                    kSCNetworkReachabilityOptionLongLivedQueryBypass,
+                                                    kCFBooleanTrue);
+                               continue;
+                       }
+
+                       if (strcasecmp(argv[i], "server") == 0) {
+                               CFDictionarySetValue(options,
+                                                    kSCNetworkReachabilityOptionServerBypass,
+                                                    kCFBooleanFalse);
+                               continue;
+                       } else if (strcasecmp(argv[i], "no-server") == 0) {
+                               CFDictionarySetValue(options,
+                                                    kSCNetworkReachabilityOptionServerBypass,
+                                                    kCFBooleanTrue);
+                               continue;
+                       }
+
+                       if (strcasecmp(argv[i], "no-resolve") == 0) {
+                               CFDictionarySetValue(options,
+                                                    kSCNetworkReachabilityOptionResolverBypass,
+                                                    kCFBooleanTrue);
+                               resolver_bypass = TRUE;
+                               continue;
+                       }
+
+                       if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) {
+                               hints.ai_flags |= AI_ADDRCONFIG;
+                       } else if (strcasecmp(argv[i], "AI_ALL") == 0) {
+                               hints.ai_flags |= AI_ALL;
+                       } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) {
+                               hints.ai_flags |= AI_V4MAPPED;
+                       } else if (strcasecmp(argv[i], "AI_V4MAPPED_CFG") == 0) {
+                               hints.ai_flags |= AI_V4MAPPED_CFG;
+                       } else if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) {
+                               hints.ai_flags |= AI_ADDRCONFIG;
+                       } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) {
+                               hints.ai_flags |= AI_V4MAPPED;
+                       } else if (strcasecmp(argv[i], "AI_DEFAULT") == 0) {
+                               hints.ai_flags |= AI_DEFAULT;
+#ifdef AI_PARALLEL
+                       } else if (strcasecmp(argv[i], "AI_PARALLEL") == 0) {
+                               hints.ai_flags |= AI_PARALLEL;
+#endif // AI_PARALLEL
+                       } else if (strcasecmp(argv[i], "PF_INET") == 0) {
+                               hints.ai_family = PF_INET;
+                       } else if (strcasecmp(argv[i], "PF_INET6") == 0) {
+                               hints.ai_family = PF_INET6;
+                       } else if (strcasecmp(argv[i], "SOCK_STREAM") == 0) {
+                               hints.ai_socktype = SOCK_STREAM;
+                       } else if (strcasecmp(argv[i], "SOCK_DGRAM") == 0) {
+                               hints.ai_socktype = SOCK_DGRAM;
+                       } else if (strcasecmp(argv[i], "SOCK_RAW") == 0) {
+                               hints.ai_socktype = SOCK_RAW;
+                       } else if (strcasecmp(argv[i], "IPPROTO_TCP") == 0) {
+                               hints.ai_protocol = IPPROTO_TCP;
+                       } else if (strcasecmp(argv[i], "IPPROTO_UDP") == 0) {
+                               hints.ai_protocol = IPPROTO_UDP;
+                       } else {
+                               SCPrint(TRUE, stderr, CFSTR("Unrecognized hint: %s\n"), argv[i]);
+                               CFRelease(options);
+                               exit(1);
+                       }
+                       n_hints++;
+               }
+
+               if (n_hints > 0) {
+                       CFDataRef       data;
+
+                       data = CFDataCreate(NULL, (const UInt8 *)&hints, sizeof(hints));
+                       CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data);
+                       CFRelease(data);
+               }
+       }
+
+       if (interface != NULL) {
+               CFStringRef     str;
+
+               if (if_nametoindex(interface) == 0) {
+                       SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface);
+                       exit(1);
+               }
+
+               str  = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII);
+               CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str);
+               CFRelease(str);
+       }
+
+       if (CFDictionaryGetCount(options) == 0) {
+               CFRelease(options);
+               options = NULL;
+       }
+
+       return options;
+}
+
 
 static SCNetworkReachabilityRef
 _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
 {
        char                            *ip_address     = argv[0];
        const char                      *interface;
+       CFMutableDictionaryRef          options         = NULL;
        struct sockaddr_in              sin;
        struct sockaddr_in6             sin6;
-       SCNetworkReachabilityRef        target  = NULL;
+       SCNetworkReachabilityRef        target          = NULL;
 
        bzero(&sin, sizeof(sin));
        sin.sin_len    = sizeof(sin);
@@ -73,37 +209,33 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
        }
 
        if (inet_aton(ip_address, &sin.sin_addr) == 1) {
-               if (argc == 1) {
-                       if (interface == NULL) {
+               if ((argc == 1) ||
+                   ((argc > 1) && (strlen(argv[1]) == 0))) {
+                       options = _setupReachabilityOptions(argc, argv, interface);
+                       if (options == NULL) {
                                target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
                                if (context != NULL) {
                                        context->info = "by address";
                                }
                        } else {
-                               CFDataRef               data;
-                               CFStringRef             str;
-                               CFMutableDictionaryRef  options;
+                               CFDataRef       data;
 
-                               if (if_nametoindex(interface) == 0) {
-                                       SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface);
-                                       exit(1);
-                               }
-
-                               options = CFDictionaryCreateMutable(NULL,
-                                                                   0,
-                                                                   &kCFTypeDictionaryKeyCallBacks,
-                                                                   &kCFTypeDictionaryValueCallBacks);
                                data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
                                CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
                                CFRelease(data);
-                               str  = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII);
-                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str);
-                               CFRelease(str);
-                               target = SCNetworkReachabilityCreateWithOptions(NULL, options);
+
                                if (context != NULL) {
-                                       context->info = "by address w/scope";
+                                       if (CFDictionaryContainsKey(options,
+                                                                   kSCNetworkReachabilityOptionInterface)) {
+                                               if (CFDictionaryGetCount(options) == 2) {
+                                                       context->info = "by address w/scope";
+                                               } else {
+                                                       context->info = "by address w/scope and options";
+                                               }
+                                       } else {
+                                               context->info = "by address w/options";
+                                       }
                                }
-                               CFRelease(options);
                        }
                } else {
                        char                    *remote_address = argv[1];
@@ -139,7 +271,8 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
                                free(remote_address);
                        }
 
-                       if (interface == NULL) {
+                       options = _setupReachabilityOptions(argc, argv, interface);
+                       if (options == NULL) {
                                target = SCNetworkReachabilityCreateWithAddressPair(NULL,
                                                                                    (struct sockaddr *)&sin,
                                                                                    (struct sockaddr *)&r_sin);
@@ -147,33 +280,27 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
                                        context->info = "by address pair";
                                }
                        } else {
-                               CFDataRef               data;
-                               CFStringRef             str;
-                               CFMutableDictionaryRef  options;
-
-                               if (if_nametoindex(interface) == 0) {
-                                       SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface);
-                                       exit(1);
-                               }
+                               CFDataRef       data;
 
-                               options = CFDictionaryCreateMutable(NULL,
-                                                                   0,
-                                                                   &kCFTypeDictionaryKeyCallBacks,
-                                                                   &kCFTypeDictionaryValueCallBacks);
                                data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin));
                                CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
                                CFRelease(data);
                                data = CFDataCreate(NULL, (const UInt8 *)&r_sin, sizeof(r_sin));
                                CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
                                CFRelease(data);
-                               str  = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII);
-                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str);
-                               CFRelease(str);
-                               target = SCNetworkReachabilityCreateWithOptions(NULL, options);
+
                                if (context != NULL) {
-                                       context->info = "by address pair w/scope";
+                                       if (CFDictionaryContainsKey(options,
+                                                                   kSCNetworkReachabilityOptionInterface)) {
+                                               if (CFDictionaryGetCount(options) == 3) {
+                                                       context->info = "by address pair w/scope";
+                                               } else {
+                                                       context->info = "by address pair w/scope and options";
+                                               }
+                                       } else {
+                                               context->info = "by address pair w/options";
+                                       }
                                }
-                               CFRelease(options);
                        }
                }
        } else if (inet_pton(AF_INET6, argv[0], &sin6.sin6_addr) == 1) {
@@ -181,10 +308,24 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
                        sin6.sin6_scope_id = if_nametoindex(interface);
                }
 
-               if (argc == 1) {
-                       target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6);
-                       if (context != NULL) {
-                               context->info = "by (v6) address";
+               if ((argc == 1) ||
+                   ((argc > 1) && (strlen(argv[1]) == 0))) {
+                       options = _setupReachabilityOptions(argc, argv, NULL);
+                       if (options == NULL) {
+                               target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6);
+                               if (context != NULL) {
+                                       context->info = "by (v6) address";
+                               }
+                       } else {
+                               CFDataRef       data;
+
+                               data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
+                               CFRelease(data);
+
+                               if (context != NULL) {
+                                       context->info = "by (v6) address w/options";
+                               }
                        }
                } else {
                        struct sockaddr_in6     r_sin6;
@@ -202,27 +343,61 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
                                r_sin6.sin6_scope_id = if_nametoindex(interface);
                        }
 
-                       target = SCNetworkReachabilityCreateWithAddressPair(NULL,
-                                                                           (struct sockaddr *)&sin6,
-                                                                           (struct sockaddr *)&r_sin6);
-                       if (context != NULL) {
-                               context->info = "by (v6) address pair";
+                       options = _setupReachabilityOptions(argc, argv, NULL);
+                       if (options == NULL) {
+                               target = SCNetworkReachabilityCreateWithAddressPair(NULL,
+                                                                                   (struct sockaddr *)&sin6,
+                                                                                   (struct sockaddr *)&r_sin6);
+                               if (context != NULL) {
+                                       context->info = "by (v6) address pair";
+                               }
+                       } else {
+                               CFDataRef       data;
+
+                               data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6));
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data);
+                               CFRelease(data);
+                               data = CFDataCreate(NULL, (const UInt8 *)&r_sin6, sizeof(r_sin6));
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data);
+                               CFRelease(data);
+
+                               if (context != NULL) {
+                                       context->info = "by (v6) address pair w/options";
+                               }
                        }
                }
        } else {
-               if (argc == 1) {
-                       target = SCNetworkReachabilityCreateWithName(NULL, argv[0]);
-                       if (context != NULL) {
-                               context->info = "by name";
+               CFStringRef     str;
+
+               options = _setupReachabilityOptions(argc, argv, NULL);
+
+               if (((argc == 1) && (strlen(argv[0]) > 0)) ||
+                   ((argc > 1) && (strlen(argv[0]) > 0) && (strlen(argv[1]) == 0))) {
+                       if (options == NULL) {
+                               target = SCNetworkReachabilityCreateWithName(NULL, argv[0]);
+                               if (context != NULL) {
+                                       context->info = "by name";
+                               }
+                       } else {
+                               str  = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
+                               CFRelease(str);
+
+                               if (context != NULL) {
+                                       context->info = "by name w/options";
+                               }
                        }
                } else {
-                       CFStringRef             str;
-                       CFMutableDictionaryRef  options;
+                       CFIndex         n_options;
+
+                       if (options == NULL) {
+                               options = CFDictionaryCreateMutable(NULL,
+                                                                   0,
+                                                                   &kCFTypeDictionaryKeyCallBacks,
+                                                                   &kCFTypeDictionaryValueCallBacks);
+                       }
+                       n_options = CFDictionaryGetCount(options);
 
-                       options = CFDictionaryCreateMutable(NULL,
-                                                           0,
-                                                           &kCFTypeDictionaryKeyCallBacks,
-                                                           &kCFTypeDictionaryValueCallBacks);
                        if (strlen(argv[0]) > 0) {
                                str  = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
                                CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str);
@@ -233,87 +408,20 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
                                CFDictionarySetValue(options, kSCNetworkReachabilityOptionServName, str);
                                CFRelease(str);
                        }
-                       if (argc > 2) {
-                               CFDataRef               data;
-                               struct addrinfo         hints   = { 0 };
-                               int                     i;
-                               int                     n_hints = 0;
-
-                               for (i = 2; i < argc; i++) {
-                                       if (strcasecmp(argv[i], "interface") == 0) {
-                                               if (++i >= argc) {
-                                                       SCPrint(TRUE, stderr, CFSTR("No interface\n"));
-                                                       CFRelease(options);
-                                                       exit(1);
-                                               }
-                                               if (if_nametoindex(argv[i]) == 0) {
-                                                       SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), argv[i]);
-                                                       CFRelease(options);
-                                                       exit(1);
-                                               }
-                                               str  = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingASCII);
-                                               CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str);
-                                               CFRelease(str);
-                                               continue;
-                                       }
 
-                                       if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) {
-                                               hints.ai_flags |= AI_ADDRCONFIG;
-                                       } else if (strcasecmp(argv[i], "AI_ALL") == 0) {
-                                               hints.ai_flags |= AI_ALL;
-                                       } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) {
-                                               hints.ai_flags |= AI_V4MAPPED;
-                                       } else if (strcasecmp(argv[i], "AI_V4MAPPED_CFG") == 0) {
-                                               hints.ai_flags |= AI_V4MAPPED_CFG;
-                                       } else if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) {
-                                               hints.ai_flags |= AI_ADDRCONFIG;
-                                       } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) {
-                                               hints.ai_flags |= AI_V4MAPPED;
-                                       } else if (strcasecmp(argv[i], "AI_DEFAULT") == 0) {
-                                               hints.ai_flags |= AI_DEFAULT;
-#ifdef AI_PARALLEL
-                                       } else if (strcasecmp(argv[i], "AI_PARALLEL") == 0) {
-                                               hints.ai_flags |= AI_PARALLEL;
-#endif // AI_PARALLEL
-                                       } else if (strcasecmp(argv[i], "PF_INET") == 0) {
-                                               hints.ai_family = PF_INET;
-                                       } else if (strcasecmp(argv[i], "PF_INET6") == 0) {
-                                               hints.ai_family = PF_INET6;
-                                       } else if (strcasecmp(argv[i], "SOCK_STREAM") == 0) {
-                                               hints.ai_socktype = SOCK_STREAM;
-                                       } else if (strcasecmp(argv[i], "SOCK_DGRAM") == 0) {
-                                               hints.ai_socktype = SOCK_DGRAM;
-                                       } else if (strcasecmp(argv[i], "SOCK_RAW") == 0) {
-                                               hints.ai_socktype = SOCK_RAW;
-                                       } else if (strcasecmp(argv[i], "IPPROTO_TCP") == 0) {
-                                               hints.ai_protocol = IPPROTO_TCP;
-                                       } else if (strcasecmp(argv[i], "IPPROTO_UDP") == 0) {
-                                               hints.ai_protocol = IPPROTO_UDP;
+                       if (CFDictionaryGetCount(options) > n_options) {
+                               if (context != NULL) {
+                                       if (n_options == 0) {
+                                               context->info = "by (node and/or serv) name";
                                        } else {
-                                               SCPrint(TRUE, stderr, CFSTR("Unrecognized hint: %s\n"), argv[i]);
-                                               CFRelease(options);
-                                               exit(1);
+                                               context->info = "by (node and/or serv) name w/options";
                                        }
-                                       n_hints++;
-                               }
-
-                               if (n_hints > 0) {
-                                       data = CFDataCreate(NULL, (const UInt8 *)&hints, sizeof(hints));
-                                       CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data);
-                                       CFRelease(data);
-                               }
-                       }
-                       if (CFDictionaryGetCount(options) > 0) {
-                               target = SCNetworkReachabilityCreateWithOptions(NULL, options);
-                               if (context != NULL) {
-                                       context->info = "by (node and/or serv) name";
                                }
                        } else {
                                SCPrint(TRUE, stderr, CFSTR("Must specify nodename or servname\n"));
                                CFRelease(options);
                                exit(1);
                        }
-                       CFRelease(options);
                }
        }
 
@@ -321,24 +429,18 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context)
                free(ip_address);
        }
 
+       if ((target == NULL) && (options != NULL)) {
+               target = SCNetworkReachabilityCreateWithOptions(NULL, options);
+               CFRelease(options);
+       }
+
        return target;
 }
 
 static void
-_printReachability(SCNetworkReachabilityRef target)
+_printReachabilityFlags(SCNetworkReachabilityFlags flags)
 {
-       SCNetworkReachabilityFlags      flags;
-       Boolean                         ok;
-
-       ok = SCNetworkReachabilityGetFlags(target, &flags);
-       if (!ok) {
-               printf("    could not determine reachability, %s\n", SCErrorString(SCError()));
-               return;
-       }
-
-       SCPrint(_sc_debug, stdout, CFSTR("flags = 0x%08x"), flags);
        if (flags != 0) {
-               SCPrint(_sc_debug, stdout, CFSTR(" ("));
                if (flags & kSCNetworkReachabilityFlagsReachable) {
                        SCPrint(TRUE, stdout, CFSTR("Reachable"));
                        flags &= ~kSCNetworkReachabilityFlagsReachable;
@@ -389,12 +491,35 @@ _printReachability(SCNetworkReachabilityRef target)
                if (flags != 0) {
                        SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
                }
-               SCPrint(_sc_debug, stdout, CFSTR(")"));
        } else {
-               SCPrint(_sc_debug, stdout, CFSTR(" ("));
                SCPrint(TRUE, stdout, CFSTR("Not Reachable"));
-               SCPrint(_sc_debug, stdout, CFSTR(")"));
        }
+
+       return;
+}
+
+static void
+_printReachability(SCNetworkReachabilityRef target)
+{
+       SCNetworkReachabilityFlags      flags;
+       Boolean                         ok;
+
+       ok = SCNetworkReachabilityGetFlags(target, &flags);
+       if (!ok) {
+               printf("    could not determine reachability, %s\n", SCErrorString(SCError()));
+               return;
+       }
+
+       SCPrint(_sc_debug, stdout, CFSTR("flags = 0x%08x ("), flags);
+       _printReachabilityFlags(flags);
+       SCPrint(_sc_debug, stdout, CFSTR(")"));
+
+       if (resolver_bypass) {
+               int if_index =
+                       SCNetworkReachabilityGetInterfaceIndex(target);
+               SCPrint(_sc_debug, stdout, CFSTR("interface index = %d"), if_index);
+       }
+
        SCPrint(TRUE, stdout, CFSTR("\n"));
 
        return;
@@ -419,6 +544,115 @@ do_checkReachability(int argc, char **argv)
 }
 
 
+static void
+_printNWIFlags(nwi_ifstate_flags flags)
+{
+       if (flags == 0) {
+               return;
+       }
+
+       SCPrint(TRUE, stdout, CFSTR(" ("));
+       if (flags & NWI_IFSTATE_FLAGS_HAS_IPV4) {
+               SCPrint(TRUE, stdout, CFSTR("IPv4"));
+               flags &= ~NWI_IFSTATE_FLAGS_HAS_IPV4;
+               SCPrint(flags != 0, stdout, CFSTR(","));
+       }
+       if (flags & NWI_IFSTATE_FLAGS_HAS_IPV6) {
+               SCPrint(TRUE, stdout, CFSTR("IPv6"));
+               flags &= ~NWI_IFSTATE_FLAGS_HAS_IPV6;
+               SCPrint(flags != 0, stdout, CFSTR(","));
+       }
+       if (flags & NWI_IFSTATE_FLAGS_HAS_DNS) {
+               SCPrint(TRUE, stdout, CFSTR("DNS"));
+               flags &= ~NWI_IFSTATE_FLAGS_HAS_DNS;
+               SCPrint(flags != 0, stdout, CFSTR(","));
+       }
+       if (flags != 0) {
+               SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
+       }
+       SCPrint(TRUE, stdout, CFSTR(")"));
+
+       return;
+}
+
+
+__private_extern__
+void
+do_nwi(int argc, char **argv)
+{
+       nwi_ifstate_t   ifstate;
+       nwi_state_t     state   = nwi_state_copy();
+
+       if (state == NULL) {
+               SCPrint(TRUE, stdout, CFSTR("No network information\n"));
+               exit(1);
+       }
+
+       if (argc > 0) {
+               ifstate = nwi_state_get_ifstate(state, argv[0]);
+               if (ifstate != NULL) {
+                       nwi_ifstate_flags       flags   = nwi_ifstate_get_flags(ifstate);
+
+                       SCPrint(TRUE, stdout, CFSTR("Network interface information\n"), argv[0]);
+                       SCPrint(TRUE, stdout,
+                               CFSTR(" %7s : flags %p"),
+                               nwi_ifstate_get_ifname(ifstate),
+                               flags);
+                       _printNWIFlags(flags);
+                       SCPrint(TRUE, stdout, CFSTR("\n"));
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]);
+               }
+
+               goto done;
+       }
+
+       SCPrint(TRUE, stdout, CFSTR("Network information\n"));
+       SCPrint(TRUE, stdout, CFSTR("\nIPv4 network interface information\n"));
+       ifstate = nwi_state_get_first_ifstate(state, AF_INET);
+
+       if (ifstate == NULL) {
+               SCPrint(TRUE, stdout, CFSTR(" No IPv4 states found\n"));
+       }
+
+       while (ifstate != NULL) {
+               nwi_ifstate_flags       flags   = nwi_ifstate_get_flags(ifstate);
+
+               SCPrint(TRUE, stdout,
+                       CFSTR(" %7s : flags %p"),
+                       nwi_ifstate_get_ifname(ifstate),
+                       flags);
+               _printNWIFlags(flags);
+               SCPrint(TRUE, stdout, CFSTR("\n"));
+               ifstate = nwi_ifstate_get_next(ifstate, AF_INET);
+       }
+
+       SCPrint(TRUE, stdout, CFSTR("\nIPv6 network interface information\n"));
+       ifstate = nwi_state_get_first_ifstate(state, AF_INET6);
+
+       if (ifstate == NULL) {
+               SCPrint(TRUE, stdout, CFSTR(" No IPv6 states found\n"));
+       }
+
+       while (ifstate != NULL) {
+               nwi_ifstate_flags       flags   = nwi_ifstate_get_flags(ifstate);
+
+               SCPrint(TRUE, stdout,
+                       CFSTR(" %7s : flags %p"),
+                       nwi_ifstate_get_ifname(ifstate),
+                       flags);
+               _printNWIFlags(flags);
+               SCPrint(TRUE, stdout, CFSTR("\n"));
+               ifstate = nwi_ifstate_get_next(ifstate, AF_INET6);
+       }
+
+    done :
+
+       nwi_state_release(state);
+       exit(0);
+}
+
+
 static void
 callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
 {
@@ -466,7 +700,7 @@ do_watchReachability(int argc, char **argv)
        // until after the "target" has been scheduled on a run loop.  Otherwise, we'll
        // end up making a synchronous DNS request and that's not what we want.
        //
-       // But, to test the case were an application call SCNetworkReachabilityGetFlags()
+       // To test the case were an application first calls SCNetworkReachabilityGetFlags()
        // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable.
        if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL) {
                CFRelease(target_async);
@@ -483,7 +717,7 @@ do_watchReachability(int argc, char **argv)
        // schedule the target
        SCPrint(TRUE, stdout, CFSTR(" 1: start\n"));
        SCPrint(TRUE, stdout, CFSTR("   %@\n"), target_async);
-       //_printReachability(target_async);
+//     _printReachability(target_async);
        SCPrint(TRUE, stdout, CFSTR("\n"));
 
        if (!SCNetworkReachabilitySetCallback(target_async, callout, &context)) {
@@ -572,6 +806,7 @@ showResolver(dns_resolver_t *resolver, int index)
                uint32_t        flags   = resolver->flags;
 
                SCPrint(TRUE, stdout, CFSTR("  flags    : "));
+               SCPrint(_sc_debug, stdout, CFSTR("0x%08x ("), flags);
                if (flags & DNS_RESOLVER_FLAGS_SCOPED) {
                        SCPrint(TRUE, stdout, CFSTR("Scoped"));
                        flags &= ~DNS_RESOLVER_FLAGS_SCOPED;
@@ -580,6 +815,17 @@ showResolver(dns_resolver_t *resolver, int index)
                if (flags != 0) {
                        SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
                }
+               SCPrint(_sc_debug, stdout, CFSTR(")"));
+               SCPrint(TRUE, stdout, CFSTR("\n"));
+       }
+
+       if (resolver->reach_flags != 0) {
+               uint32_t        flags   = resolver->reach_flags;
+
+               SCPrint(TRUE, stdout, CFSTR("  reach    : "));
+               SCPrint(_sc_debug, stdout, CFSTR("0x%08x ("), flags);
+               _printReachabilityFlags(flags);
+               SCPrint(_sc_debug, stdout, CFSTR(")"));
                SCPrint(TRUE, stdout, CFSTR("\n"));
        }
 
@@ -595,10 +841,56 @@ __private_extern__
 void
 do_showDNSConfiguration(int argc, char **argv)
 {
-       dns_config_t    *dns_config;
+       dns_config_t                    *dns_config;
+       SCNetworkReachabilityRef        target;
 
        dns_config = dns_configuration_copy();
-       if (dns_config) {
+
+       if (dns_config == NULL) {
+               SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
+               exit(1);
+       }
+
+       if (argc > 1) {
+               int                             dns_config_index        = -1;
+               SCNetworkReachabilityFlags      flags                   = 0;
+               Boolean                         haveDNS                 = FALSE;
+               Boolean                         ok                      = FALSE;
+               dns_resolver_t                  *resolver;
+               uint32_t                        resolver_if_index;
+               SCNetworkReachabilityPrivateRef targetPrivate;
+
+               target = _setupReachability(argc, argv, NULL);
+
+               targetPrivate = (SCNetworkReachabilityPrivateRef)target;
+
+               if (targetPrivate->type != reachabilityTypeName) {
+                       SCPrint(TRUE, stdout, CFSTR("\"%s\" is not a hostname.\n"), argv[0]);
+                       exit(1);
+               }
+
+               ok = __SC_checkResolverReachabilityInternal(&store, &flags,
+                                                           &haveDNS, targetPrivate->name, NULL,
+                                                           &resolver_if_index, &dns_config_index);
+
+               if (!ok) {
+                       SCPrint(TRUE, stdout, CFSTR("No DNS configuration available.\n" ));
+                       exit(1);
+               }
+
+               SCPrint(TRUE, stdout, CFSTR("DNS configuration for %s\n"),
+                       targetPrivate->name);
+
+               if (targetPrivate->if_index == 0) {
+                       resolver = dns_config->resolver[dns_config_index];
+               } else {
+                       resolver = dns_config->scoped_resolver[dns_config_index];
+               }
+
+               showResolver(resolver, dns_config_index + 1);
+
+               if (target != NULL) CFRelease(target);
+       } else {
                int     i;
 
                SCPrint(TRUE, stdout, CFSTR("DNS configuration\n"));
@@ -618,12 +910,9 @@ do_showDNSConfiguration(int argc, char **argv)
                                showResolver(resolver, i + 1);
                        }
                }
-
-               dns_configuration_free(dns_config);
-       } else {
-               SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n"));
        }
 
+       dns_configuration_free(dns_config);
        exit(0);
 }
 
@@ -746,6 +1035,11 @@ do_snapshot(int argc, char **argv)
        if (!SCDynamicStoreSnapshot(store)) {
                SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
        }
+
+#ifdef HAVE_REACHABILITY_SERVER
+       (void) _SCNetworkReachabilityServer_snapshot();
+#endif // HAVE_REACHABILITY_SERVER
+
        return;
 }
 
index 6de629b3d0422bfbaee4599cd5d076ea4d8b0dfd..6b5c0e9ad8e9a00f187fd1022255a6419e85984a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2004, 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004, 2007, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -46,6 +46,7 @@ void  do_showDNSConfiguration         (int argc, char **argv);
 void   do_showProxyConfiguration       (int argc, char **argv);
 void   do_snapshot                     (int argc, char **argv);
 void   do_wait                         (char *waitKey, int timeout);
+void   do_nwi                          (int argc, char **argv);
 
 __END_DECLS