Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
SimpleReach.c
/* |
File: SimpleReach.c |
Contains: Demonstrates the System Configuration framework reachability APIs. |
Written by: DTS |
Copyright: Copyright (c) 2004 by Apple Computer, Inc., All Rights Reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under Apple's |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
$Log: SimpleReach.c,v $ |
Revision 1.2 2004/05/24 21:43:09 eskimo1 |
Added comments explain why I have cleanup code even though it's not entirely necessary. |
Revision 1.1 2004/04/28 15:44:36 eskimo1 |
First checked in. |
*/ |
#include <assert.h> |
#include <errno.h> |
#include <CoreFoundation/CoreFoundation.h> |
#include <SystemConfiguration/SystemConfiguration.h> |
static void CleanupTarget(SCNetworkReachabilityRef thisTarget) |
// Disposes of thisTarget. |
{ |
assert(thisTarget != NULL); |
// Ignore the result from SCNetworkReachabilityUnscheduleFromRunLoop. |
// It basically tells us whether thisTarget was successfully removed |
// from the runloop. It will be false if we never added thisTarget |
// to the runloop, which is a definite possibility under error |
// conditions. |
(void) SCNetworkReachabilityUnscheduleFromRunLoop( |
thisTarget, |
CFRunLoopGetCurrent(), |
kCFRunLoopDefaultMode |
); |
CFRelease(thisTarget); |
} |
static void PrintHeader(void) |
// Prints an explanation of the flag coding. |
{ |
fprintf(stdout, "t = kSCNetworkFlagsTransientConnection\n"); |
fprintf(stdout, "r = kSCNetworkFlagsReachable\n"); |
fprintf(stdout, "c = kSCNetworkFlagsConnectionRequired\n"); |
fprintf(stdout, "C = kSCNetworkFlagsConnectionAutomatic\n"); |
fprintf(stdout, "i = kSCNetworkFlagsInterventionRequired\n"); |
fprintf(stdout, "l = kSCNetworkFlagsIsLocalAddress\n"); |
fprintf(stdout, "d = kSCNetworkFlagsIsDirect\n"); |
fprintf(stdout, "\n"); |
} |
static void PrintReachabilityFlags( |
const char * hostname, |
SCNetworkConnectionFlags flags, |
const char * comment |
) |
// Prints a line that records a reachability transition. |
// This includes the current time, the new state of the |
// reachability flags (from the flags parameter), and the |
// name of the host (from the hostname parameter). |
{ |
time_t now; |
struct tm nowLocal; |
char nowLocalStr[30]; |
assert(hostname != NULL); |
if (comment == NULL) { |
comment = ""; |
} |
(void) time(&now); |
(void) localtime_r(&now, &nowLocal); |
(void) strftime(nowLocalStr, sizeof(nowLocalStr), "%X", &nowLocal); |
fprintf(stdout, "%s %c%c%c%c%c%c%c %s%s\n", |
nowLocalStr, |
(flags & kSCNetworkFlagsTransientConnection) ? 't' : '-', |
(flags & kSCNetworkFlagsReachable) ? 'r' : '-', |
(flags & kSCNetworkFlagsConnectionRequired) ? 'c' : '-', |
(flags & kSCNetworkFlagsConnectionAutomatic) ? 'C' : '-', |
(flags & kSCNetworkFlagsInterventionRequired) ? 'i' : '-', |
(flags & kSCNetworkFlagsIsLocalAddress) ? 'l' : '-', |
(flags & kSCNetworkFlagsIsDirect) ? 'd' : '-', |
hostname, |
comment |
); |
} |
static void MyReachabilityCallback( |
SCNetworkReachabilityRef target, |
SCNetworkConnectionFlags flags, |
void * info |
) |
// This routine is a System Configuration framework callback that |
// indicates that the reachability of a given host has changed. |
// It's call from the runloop. target is the host whose reachability |
// has changed, the flags indicate the new reachability status, and |
// info is the context parameter that we passed in when we registered |
// the callback. In this case, info is a pointer to the host name. |
// |
// Our response to this notification is simply to print a line |
// recording the transition. |
{ |
assert(target != NULL); |
assert(info != NULL); |
PrintReachabilityFlags( (const char *) info, flags, NULL ); |
} |
int main (int argc, const char * argv[]) |
// This program treats each of its arguments as a network host |
// name. It monitors the reachability of each host, printing |
// out a record of each change of reachability. |
{ |
int err; |
int argIndex; |
SCNetworkReachabilityRef * targets; |
Boolean ok; |
targets = NULL; |
// If we're run with no arguments, 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 hostname...\n", programName); |
err = ECANCELED; |
} |
// We allocate an array to hold all of the SCNetworkReachabilityRefs |
// that we create. The 0'th slot of this array is never used, but |
// wasting that trivial amount of memory makes the code easier. |
if (err == 0) { |
targets = malloc(argc * sizeof(*targets)); |
if (targets == NULL) { |
err = ENOMEM; |
} |
} |
// Create a SCNetworkReachabilityRef for each argument. |
if (err == 0) { |
PrintHeader(); |
fprintf(stdout, "Hit ^C to exit.\n"); |
fflush(stdout); |
for (argIndex = 1; argIndex < argc; argIndex++) { |
SCNetworkReachabilityRef thisTarget; |
SCNetworkReachabilityContext thisContext; |
thisContext.version = 0; |
thisContext.info = (void *) argv[argIndex]; |
thisContext.retain = NULL; |
thisContext.release = NULL; |
thisContext.copyDescription = NULL; |
// Create the target with the name taken from the command |
// line arguments. |
thisTarget = SCNetworkReachabilityCreateWithName( |
NULL, |
argv[argIndex] |
); |
if (thisTarget == NULL) { |
err = SCError(); |
} |
// Set our callback and install on the runloop. |
if (err == 0) { |
ok = SCNetworkReachabilitySetCallback( |
thisTarget, |
MyReachabilityCallback, |
&thisContext |
); |
if ( ! ok ) { |
err = SCError(); |
} |
} |
if (err == 0) { |
ok = SCNetworkReachabilityScheduleWithRunLoop( |
thisTarget, |
CFRunLoopGetCurrent(), |
kCFRunLoopDefaultMode |
); |
if ( ! ok ) { |
err = SCError(); |
} |
} |
if (err == 0) { |
SCNetworkConnectionFlags flags; |
ok = SCNetworkReachabilityGetFlags(thisTarget, &flags); |
if ( ok ) { |
PrintReachabilityFlags( |
argv[argIndex], |
flags, |
" (from main)" |
); |
} else { |
err = SCError(); |
} |
} |
// Record the reference in the targets array, or clean it |
// up and bail. |
if (err == 0) { |
targets[argIndex] = thisTarget; |
} else { |
if (thisTarget != NULL) { |
CleanupTarget(thisTarget); |
} |
break; |
} |
} |
} |
// If everything went well, run our runloop to handle asynchronous |
// notification of reachability changes. |
if (err == noErr) { |
CFRunLoopRun(); |
} |
// Clean up. |
// The current implementation never gets to this point in the success |
// case because the way we terminate the program is with ^C (SIGINT), |
// which just quits the program. Alas, there's no easy way to |
// integrate signal handling into a CFRunLoop <rdar://problem/3635076>. |
// However, I wanted to leave the termination code around, just to show |
// how to do it properly. |
if (targets != NULL) { |
int i; |
for (i = 1; i < argIndex; i++) { |
assert(targets[i] != NULL); |
CleanupTarget(targets[i]); |
} |
free(targets); |
} |
if (err == 0) { |
return EXIT_SUCCESS; |
} else { |
if (err != ECANCELED) { |
fprintf(stderr, "Failed with error %d\n.", err); |
} |
return EXIT_FAILURE; |
} |
} |
Copyright © 2005 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2005-07-26