From: Guus Sliepen Date: Fri, 2 Apr 2021 19:04:07 +0000 (+0200) Subject: Use SCNetworkReachability on macOS and iOS to detect network changes. X-Git-Url: http://git.meshlink.io/?p=meshlink;a=commitdiff_plain;h=53926994e1cae3d743b8a7f172c1a177fece51a7 Use SCNetworkReachability on macOS and iOS to detect network changes. Unfortunately, using SCDynamicStore*() functions to monitor network changes is not supported in iOS. Instead, we now use SCNetworkReachability*() functions which are supported on both macOS and iOS. --- diff --git a/configure.ac b/configure.ac index 592fb15d..efc306c4 100644 --- a/configure.ac +++ b/configure.ac @@ -42,7 +42,7 @@ case $host_os in LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32" ;; *darwin*) - LIBS="$LIBS -framework SystemConfiguration -framework CoreServices" + LIBS="$LIBS -framework Foundation -framework SystemConfiguration" ;; esac diff --git a/src/discovery.c b/src/discovery.c index 5cc1d412..948d786e 100644 --- a/src/discovery.c +++ b/src/discovery.c @@ -683,26 +683,26 @@ static void netlink_io_handler(event_loop_t *loop, void *data, int flags) { if(loop->now.tv_sec > mesh->discovery.last_update + 5) { mesh->discovery.last_update = loop->now.tv_sec; - handle_network_change(mesh, 1); + handle_network_change(mesh, true); } } } } #elif defined(__APPLE__) -static void network_change_callback(SCDynamicStoreRef store, CFArrayRef keys, void *info) { - (void)store; - (void)keys; +static void reachability_change_callback(SCNetworkReachabilityRef reachability, SCNetworkReachabilityFlags flags, void *info) { + (void)reachability; + (void)flags; meshlink_handle_t *mesh = info; pthread_mutex_lock(&mesh->mutex); - logger(mesh, MESHLINK_ERROR, "Network change detected!"); scan_ifaddrs(mesh); if(mesh->loop.now.tv_sec > mesh->discovery.last_update + 5) { + logger(mesh, MESHLINK_INFO, "Network change detected"); mesh->discovery.last_update = mesh->loop.now.tv_sec; - handle_network_change(mesh, 1); + handle_network_change(mesh, true); } pthread_mutex_unlock(&mesh->mutex); @@ -713,78 +713,42 @@ static void *network_change_handler(void *arg) { mesh->discovery.runloop = CFRunLoopGetCurrent(); - SCDynamicStoreContext context = {0, mesh, NULL, NULL, NULL}; - SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("network_change_handler"), network_change_callback, &context); - CFStringRef interfaces = SCDynamicStoreKeyCreate(NULL, CFSTR("State:/Network/Interface"), kCFStringEncodingUTF8); - CFStringRef ipv4 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4); - CFStringRef ipv6 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6); - CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFRunLoopSourceRef runloop_source = NULL; - - if(!store) { - logger(mesh, MESHLINK_ERROR, "Error setting up network change handler: %s\n", SCErrorString(SCError())); - goto exit; - } - - if(!interfaces || !ipv4 || !ipv6 || !keys || !patterns) { - logger(mesh, MESHLINK_ERROR, "Error setting up network change handler: %s\n", SCErrorString(SCError())); - goto exit; - } + SCNetworkReachabilityRef reach_v4 = SCNetworkReachabilityCreateWithName(NULL, "93.184.216.34"); + SCNetworkReachabilityRef reach_v6 = SCNetworkReachabilityCreateWithName(NULL, "2606:2800:220:1:248:1893:25c8:1946"); - CFArrayAppendValue(keys, interfaces); - CFArrayAppendValue(patterns, ipv4); - CFArrayAppendValue(patterns, ipv6); + SCNetworkReachabilityContext context; + memset(&context, 0, sizeof(context)); + context.info = mesh; - if(!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) { - logger(mesh, MESHLINK_ERROR, "Error setting up network change handler: %s\n", SCErrorString(SCError())); - goto exit; + if(reach_v4) { + SCNetworkReachabilitySetCallback(reach_v4, reachability_change_callback, &context); + SCNetworkReachabilityScheduleWithRunLoop(reach_v4, mesh->discovery.runloop, kCFRunLoopDefaultMode); + } else { + logger(mesh, MESHLINK_ERROR, "Could not create IPv4 network reachability watcher"); } - runloop_source = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); - - if(!runloop_source) { - logger(mesh, MESHLINK_ERROR, "Error setting up network change handler: %s\n", SCErrorString(SCError())); - goto exit; + if(reach_v6) { + SCNetworkReachabilitySetCallback(reach_v6, reachability_change_callback, &context); + SCNetworkReachabilityScheduleWithRunLoop(reach_v6, mesh->discovery.runloop, kCFRunLoopDefaultMode); + } else { + logger(mesh, MESHLINK_ERROR, "Could not create IPv6 network reachability watcher"); } - CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop_source, kCFRunLoopDefaultMode); CFRunLoopRun(); -exit: - - if(runloop_source) { - CFRelease(runloop_source); - } - - if(interfaces) { - CFRelease(interfaces); - } - - if(ipv4) { - CFRelease(ipv4); - } - - if(ipv6) { - CFRelease(ipv6); - } - - if(keys) { - CFRelease(keys); - } + mesh->discovery.runloop = NULL; - if(patterns) { - CFRelease(patterns); + if(reach_v4) { + SCNetworkReachabilityUnscheduleFromRunLoop(reach_v4, mesh->discovery.runloop, kCFRunLoopDefaultMode); + CFRelease(reach_v4); } - if(store) { - CFRelease(store); + if(reach_v6) { + SCNetworkReachabilityUnscheduleFromRunLoop(reach_v6, mesh->discovery.runloop, kCFRunLoopDefaultMode); + CFRelease(reach_v6); } - mesh->discovery.runloop = NULL; - return NULL; - } #elif defined(RTM_NEWADDR) static void pfroute_parse_iface(meshlink_handle_t *mesh, const struct rt_msghdr *rtm) {