+
+ SCPrint(TRUE, stdout, CFSTR("\n generation %llu\n"),
+ nwi_ifstate_get_generation(ifstate));
+
+ return;
+}
+
+
+static void
+_printNWIReachInfo(nwi_state_t state, int af)
+{
+ uint32_t reach_flags;
+ CFStringRef str;
+
+ reach_flags = nwi_state_get_reachability_flags(state, af);
+
+ str = __SCNetworkReachabilityCopyFlags(reach_flags, CFSTR(" REACH : flags "), TRUE);
+ SCPrint(TRUE, stdout, CFSTR("\n%@\n"), str);
+ CFRelease(str);
+
+ return;
+}
+
+
+static void
+do_printNWI(int argc, char **argv, nwi_state_t state)
+{
+ unsigned int count;
+ nwi_ifstate_t ifstate;
+
+ if (state == NULL) {
+ SCPrint(TRUE, stdout, CFSTR("No network information\n"));
+ return;
+ }
+
+ if (argc > 0) {
+ ifstate = nwi_state_get_ifstate(state, argv[0]);
+ if (ifstate != NULL) {
+ nwi_ifstate_t alias;
+
+ _printNWIInfo(ifstate);
+
+ alias = nwi_ifstate_get_alias(ifstate,
+ ifstate->af == AF_INET ? AF_INET6 : AF_INET);
+ if (alias != NULL) {
+ SCPrint(TRUE, stdout, CFSTR("\n"));
+ _printNWIInfo(alias);
+ }
+ } else {
+ SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]);
+ }
+ return;
+ }
+
+ SCPrint(TRUE, stdout, CFSTR("Network information (generation %llu)"),
+ nwi_state_get_generation(state));
+
+ 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"));
+ } else {
+ while (ifstate != NULL) {
+ _printNWIInfo(ifstate);
+ ifstate = nwi_ifstate_get_next(ifstate, AF_INET);
+ }
+ }
+ _printNWIReachInfo(state, 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"));
+ } else {
+ while (ifstate != NULL) {
+ _printNWIInfo(ifstate);
+ ifstate = nwi_ifstate_get_next(ifstate, AF_INET6);
+ }
+ }
+ _printNWIReachInfo(state, AF_INET6);
+
+ count = nwi_state_get_interface_names(state, NULL, 0);
+ if (count > 0) {
+ const char * names[count];
+
+ count = nwi_state_get_interface_names(state, names, count);
+ if (count > 0) {
+ int i;
+
+ printf("\nNetwork interfaces:");
+ for (i = 0; i < count; i++) {
+ printf(" %s", names[i]);
+ }
+ printf("\n");
+ }
+ }
+ return;
+}
+
+
+__private_extern__
+void
+do_showNWI(int argc, char **argv)
+{
+ nwi_state_t state;
+
+ state = nwi_state_copy();
+ do_printNWI(argc, argv, state);
+ if (state != NULL) {
+ nwi_state_release(state);
+ } else {
+ exit(1);
+ }
+
+ exit(0);
+}
+
+
+__private_extern__
+void
+do_watchNWI(int argc, char **argv)
+{
+ nwi_state_t state;
+ int status;
+ int token;
+
+ state = nwi_state_copy();
+ do_printNWI(argc, argv, state);
+ if (state != NULL) {
+ nwi_state_release(state);
+ }
+
+ status = notify_register_dispatch(nwi_state_get_notify_key(),
+ &token,
+ dispatch_get_main_queue(),
+ ^(int token){
+ nwi_state_t state;
+ struct tm tm_now;
+ struct timeval tv_now;
+
+ (void)gettimeofday(&tv_now, NULL);
+ (void)localtime_r(&tv_now.tv_sec, &tm_now);
+ SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
+ tm_now.tm_hour,
+ tm_now.tm_min,
+ tm_now.tm_sec,
+ tv_now.tv_usec / 1000);
+
+ state = nwi_state_copy();
+ do_printNWI(argc, argv, state);
+ if (state != NULL) {
+ nwi_state_release(state);
+ }
+ });
+ if (status != NOTIFY_STATUS_OK) {
+ SC_log(LOG_INFO, "notify_register_dispatch() failed for nwi changes, status=%u", status);
+ exit(1);
+ }
+
+ CFRunLoopRun();
+ exit(0);
+}
+
+
+static void
+callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
+{
+ static int n = 3;
+ struct tm tm_now;
+ struct timeval tv_now;
+
+ (void)gettimeofday(&tv_now, NULL);
+ (void)localtime_r(&tv_now.tv_sec, &tm_now);
+
+ SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
+ tm_now.tm_hour,
+ tm_now.tm_min,
+ tm_now.tm_sec,
+ tv_now.tv_usec / 1000);
+ SCPrint(TRUE, stdout, CFSTR("%2d: callback w/flags=0x%08x (info=\"%s\")\n"), n++, flags, (char *)info);
+ SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
+ _printReachability(target);
+ SCPrint(TRUE, stdout, CFSTR("\n"));
+ return;
+}
+
+
+__private_extern__
+void
+do_watchReachability(int argc, char **argv)
+{
+ SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
+ SCNetworkReachabilityRef target;
+ SCNetworkReachabilityRef target_async;
+
+ target = _setupReachability(argc, argv, NULL);
+ if (target == NULL) {
+ SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
+ exit(1);
+ }
+
+ target_async = _setupReachability(argc, argv, &context);
+ if (target_async == NULL) {
+ SCPrint(TRUE, stderr, CFSTR(" Could not determine status: %s\n"), SCErrorString(SCError()));
+ exit(1);
+ }
+
+ // Normally, we don't want to make any calls to SCNetworkReachabilityGetFlags()
+ // 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.
+ //
+ // 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);
+ target_async = CFRetain(target);
+ }
+
+ // Direct check of reachability
+ SCPrint(TRUE, stdout, CFSTR(" 0: direct\n"));
+ SCPrint(TRUE, stdout, CFSTR(" %@\n"), target);
+ _printReachability(target);
+ CFRelease(target);