// // Reachability.m // MBMenuExtra // // Created by Michael Bishop on 12/22/09. // Copyright 2009 Perforce Software. All rights reserved. // #import "NGAReachability.h" 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 ); } void ReachabilityCallback( SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info ); @interface NGAReachability () -(void)MB_reachabilityFlagsDidChange:(SCNetworkReachabilityFlags)flags; @end @implementation NGAReachability -(id)initWithName:(NSString*)name { if ( (self = [super init]) == nil ) return nil; reachabilityRef = SCNetworkReachabilityCreateWithName( kCFAllocatorDefault, [name UTF8String] ); _context.version = 0; _context.info = self; if ( !reachabilityRef ) return nil; SCNetworkReachabilitySetCallback( reachabilityRef, ReachabilityCallback, &_context ); _name = [name retain]; return self; } -(void)dealloc { [self stop]; NSAssert( _block == nil, @"_block should be nil from stopping in the stop method" ); if ( reachabilityRef ) CFRelease(reachabilityRef); [_name release]; [super dealloc]; } -(BOOL)startWithBlock:(ReachabilityCallbackBlock)block; { if ( reachabilityRef == NULL ) return NO; if ( block != _block ) { [_block release]; _block = [block copy]; } SCNetworkReachabilityScheduleWithRunLoop( reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); return YES; } -(BOOL)stop { [_block release]; _block = nil; if ( reachabilityRef == NULL ) return YES; return SCNetworkReachabilityUnscheduleFromRunLoop( reachabilityRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode ); } -(void)MB_reachabilityFlagsDidChange:(SCNetworkReachabilityFlags)flags { // PrintReachabilityFlags( [_name UTF8String], flags, NULL ); _block( flags ); } - (BOOL)isReachableWithoutRequiringConnection:(SCNetworkReachabilityFlags)flags { // kSCNetworkReachabilityFlagsReachable indicates that the specified nodename or address can // be reached using the current network configuration. BOOL isReachable = flags & kSCNetworkReachabilityFlagsReachable; // This flag indicates that the specified nodename or address can // be reached using the current network configuration, but a // connection must first be established. // // If the flag is false, we don't have a connection. But because CFNetwork // automatically attempts to bring up a WWAN connection, if the WWAN reachability // flag is present, a connection is not required. BOOL noConnectionRequired = !(flags & kSCNetworkReachabilityFlagsConnectionRequired); return (isReachable && noConnectionRequired) ? YES : NO; } @end void ReachabilityCallback( SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { NGAReachability * reachability = (NGAReachability*)info; [reachability MB_reachabilityFlagsDidChange:flags]; }