static void MyNetworkConnectionCallBack( SCNetworkConnectionRef connection, SCNetworkConnectionStatus status, void *info ) // Our network connection callback. Called out of the runloop // when there's a change in the status of the network connection. // It can be called as part of both a connection attempt and a // disconnection attempt. // // In response to this callback we do two things: // // 1. Print the current connection status. // 2. Once the [dis]connection attempt is resolved (the status // hits either 'connected' or 'disconnected'), we stop // the runloop. This has the effect of breaking the "main" // function out of its called to CFRunLoopRun, after which // it can examine the results of the connection. // // The "info" parameter is a pointer to our per-connection data. // In this case we use this as a pointer to a CallbackParams // structure. We use this to track the previous state of the // connection so that we don't print redundant status changes. { CallbackParams * params; SCNetworkConnectionPPPStatus minorStatus; time_t now; struct tm nowLocal; char nowLocalStr[30]; Boolean printMinorStatus; assert(connection != NULL); assert(info != NULL); params = (CallbackParams *) info; assert(params->magic = kCallbackParamsMagic); // Get a string that represents the current time. (void) time(&now); (void) localtime_r(&now, &nowLocal); (void) strftime(nowLocalStr, sizeof(nowLocalStr), "%X", &nowLocal); // Due to a bug <rdar://problem/3725976>, it's best to get the major status via // SCNetworkConnectionGetStatus than rely on the value being passed into // the callback. status = SCNetworkConnectionGetStatus(connection); // Get the minor status from the extended status associated with // the connection. minorStatus = GetMinorStatus(connection); // Print any status changes. printMinorStatus = (params->lastMinorStatus != minorStatus); if ( (params->forcePrintStatus) || (params->lastMajorStatus != status) ) { fprintf( stderr, "%s %s (%ld)\n", nowLocalStr, StatusToString(status), (long) status ); printMinorStatus = true; params->forcePrintStatus = false; } if (printMinorStatus) { fprintf( stderr, "%s %s (%ld)\n", nowLocalStr, MinorStatusToString(minorStatus), (long) minorStatus ); } // If we hit either the connected or disconnected state, // we signal the runloop to stop so that the main function // can process the result of the [dis]connection attempt. if ( ( minorStatus == kSCNetworkConnectionPPPDisconnected ) || ( minorStatus == kSCNetworkConnectionPPPConnected ) ) { CFRunLoopStop(CFRunLoopGetCurrent()); } // Record the new status. params->lastMajorStatus = status; params->lastMinorStatus = minorStatus; }
static void nc_watch(int argc, char **argv) { SCNetworkConnectionStatus status; nc_create_connection(argc, argv, TRUE); status = SCNetworkConnectionGetStatus(connection); // report initial status n_callback = 0; nc_callback(connection, status, &n_callback); // setup watcher if (doDispatch) { if (!SCNetworkConnectionSetDispatchQueue(connection, dispatch_get_main_queue())) { SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); exit(1); } } else { if (!SCNetworkConnectionScheduleWithRunLoop(connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); exit(1); } } // wait for changes CFRunLoopRun(); nc_release_connection(); exit(0); }
/* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ static void nc_status(int argc, char **argv) { SCNetworkConnectionStatus status; nc_create_connection(argc, argv, TRUE); status = SCNetworkConnectionGetStatus(connection); nc_callback(connection, status, NULL); nc_release_connection(); exit(0); }
CFStringRef copy_VPN_status(SCNetworkServiceRef service) { CFStringRef output = NULL; SCNetworkConnectionStatus status = kSCNetworkConnectionInvalid; SCNetworkConnectionRef service_connection = NULL; /* Only calculate status is the service is enabled. Default is invalid. */ if (SCNetworkServiceGetEnabled(service)) { service_connection = SCNetworkConnectionCreateWithService(NULL, service, NULL, NULL); if (service_connection == NULL) goto done; status = SCNetworkConnectionGetStatus(service_connection); } output = CFStringCreateWithCString(NULL, nc_status_string(status), kCFStringEncodingUTF8); done: my_CFRelease(&service_connection); return output; }
int main (int argc, const char * argv[]) // This program finds the first PPP connection service in the // current network configuration and then connects and // disconnects that service. { int err; Boolean ok; CFStringRef serviceToDial; CFDictionaryRef optionsForDial; SCNetworkConnectionRef connection; CallbackParams params; serviceToDial = NULL; optionsForDial = NULL; connection = NULL; // If we're run without an argument, just print the usage. err = 0; if (argc != 1) { const char *programName; programName = strrchr(argv[0], '/'); if (programName == NULL) { programName = argv[0]; } else { programName += 1; } fprintf(stderr, "Usage: %s\n", programName); err = ECANCELED; } // Find the serviceID of the PPP service to dial and the user's // preferred dialling options. This routine picks up the last // service dialled using Internet Connect (and the associated // options) or, if Internet Connect has not been used, returns // the first PPP service listed in the Network preferences pane. if (err == 0) { ok = SCNetworkConnectionCopyUserPreferences( NULL, &serviceToDial, &optionsForDial ); if ( ! ok ) { err = SCError(); } } // Create a SCNetworkConnectionRef for it. if (err == 0) { SCNetworkConnectionContext context; // Set up the parameters to our callback function. params.magic = kCallbackParamsMagic; params.forcePrintStatus = true; params.lastMinorStatus = kSCNetworkConnectionDisconnected; params.lastMinorStatus = kSCNetworkConnectionPPPDisconnected; // Set up the context to reference those parameters. context.version = 0; context.info = (void *) ¶ms; context.retain = NULL; context.release = NULL; context.copyDescription = NULL; connection = SCNetworkConnectionCreateWithServiceID( NULL, serviceToDial, MyNetworkConnectionCallBack, &context ); if (connection == NULL) { err = SCError(); } } // Schedule our callback with the runloop. if (err == 0) { ok = SCNetworkConnectionScheduleWithRunLoop( connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); if ( ! ok ) { err = SCError(); } } // Check the status. If we're already connected tell the user. // If we're not connected, initiate the connection. if (err == 0) { err = ECANCELED; // Most cases involve us bailing out, // so set the error here. switch ( SCNetworkConnectionGetStatus(connection) ) { case kSCNetworkConnectionDisconnected: err = 0; break; case kSCNetworkConnectionConnecting: fprintf(stderr, "Service is already connecting.\n"); break; case kSCNetworkConnectionDisconnecting: fprintf(stderr, "Service is disconnecting.\n"); break; case kSCNetworkConnectionConnected: fprintf(stderr, "Service is already connected.\n"); break; case kSCNetworkConnectionInvalid: fprintf(stderr, "Service is invalid. Weird.\n"); break; default: fprintf(stderr, "Unexpected status.\n"); break; } } // Initiate the connection. if (err == 0) { fprintf(stderr, "Connecting...\n"); ok = SCNetworkConnectionStart( connection, optionsForDial, false ); if ( ! ok ) { err = SCError(); } } // Run the runloop and wait for our connection attempt to be resolved. // Once that happens, print the result. if (err == 0) { CFRunLoopRun(); switch (params.lastMinorStatus) { case kSCNetworkConnectionPPPConnected: fprintf(stderr, "Connection succeeded\n"); break; case kSCNetworkConnectionPPPDisconnected: fprintf(stderr, "Connection failed\n"); err = ECANCELED; break; default: fprintf( stderr, "Bad params.lastMinorStatus (%ld)\n", (long) params.lastMinorStatus ); err = EINVAL; break; } } // Wait for a few seconds. if (err == 0) { fprintf(stderr, "Waiting for a few seconds...\n"); (void) sleep(5); // Initiate a disconnect. params.forcePrintStatus = true; fprintf(stderr, "Disconnecting...\n"); ok = SCNetworkConnectionStop( connection, true ); if ( ! ok ) { err = SCError(); } } // Run the runloop and wait for our disconnection attempt to be // resolved. Once that happens, print the result. if (err == 0) { CFRunLoopRun(); switch (params.lastMinorStatus) { case kSCNetworkConnectionPPPDisconnected: fprintf(stderr, "Disconnection succeeded\n"); break; case kSCNetworkConnectionPPPConnected: fprintf(stderr, "Disconnection failed\n"); err = ECANCELED; break; default: fprintf( stderr, "Bad params.lastMinorStatus (%ld)\n", (long) params.lastMinorStatus ); err = EINVAL; break; } } // Clean up. if (serviceToDial != NULL) { CFRelease(serviceToDial); } if (optionsForDial != NULL) { CFRelease(optionsForDial); } if (connection != NULL) { (void) SCNetworkConnectionUnscheduleFromRunLoop( connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); CFRelease(connection); } if (err == 0) { return EXIT_SUCCESS; } else { if (err != ECANCELED) { fprintf(stderr, "Failed with error %d\n.", err); } return EXIT_FAILURE; } }