Blame client/iOS/Misc/Reachability.m

Packit 1fb8d4
/*
Packit 1fb8d4
 
Packit 1fb8d4
 File: Reachability.m
Packit 1fb8d4
 Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
Packit 1fb8d4
 
Packit 1fb8d4
 Version: 2.2
Packit 1fb8d4
 
Packit 1fb8d4
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Inc.
Packit 1fb8d4
 ("Apple") in consideration of your agreement to the following terms, and your
Packit 1fb8d4
 use, installation, modification or redistribution of this Apple software
Packit 1fb8d4
 constitutes acceptance of these terms.  If you do not agree with these terms,
Packit 1fb8d4
 please do not use, install, modify or redistribute this Apple software.
Packit 1fb8d4
 
Packit 1fb8d4
 In consideration of your agreement to abide by the following terms, and subject
Packit 1fb8d4
 to these terms, Apple grants you a personal, non-exclusive license, under
Packit 1fb8d4
 Apple's copyrights in this original Apple software (the "Apple Software"), to
Packit 1fb8d4
 use, reproduce, modify and redistribute the Apple Software, with or without
Packit 1fb8d4
 modifications, in source and/or binary forms; provided that if you redistribute
Packit 1fb8d4
 the Apple Software in its entirety and without modifications, you must retain
Packit 1fb8d4
 this notice and the following text and disclaimers in all such redistributions
Packit 1fb8d4
 of the Apple Software.
Packit 1fb8d4
 Neither the name, trademarks, service marks or logos of Apple Inc. may be used
Packit 1fb8d4
 to endorse or promote products derived from the Apple Software without specific
Packit 1fb8d4
 prior written permission from Apple.  Except as expressly stated in this notice,
Packit 1fb8d4
 no other rights or licenses, express or implied, are granted by Apple herein,
Packit 1fb8d4
 including but not limited to any patent rights that may be infringed by your
Packit 1fb8d4
 derivative works or by other works in which the Apple Software may be
Packit 1fb8d4
 incorporated.
Packit 1fb8d4
 
Packit 1fb8d4
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
Packit 1fb8d4
 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
Packit 1fb8d4
 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
Packit 1fb8d4
 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
Packit 1fb8d4
 COMBINATION WITH YOUR PRODUCTS.
Packit 1fb8d4
 
Packit 1fb8d4
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
Packit 1fb8d4
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
Packit 1fb8d4
 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 1fb8d4
 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
Packit 1fb8d4
 DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
Packit 1fb8d4
 CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
Packit 1fb8d4
 APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 1fb8d4
 
Packit 1fb8d4
 Copyright (C) 2010 Apple Inc. All Rights Reserved.
Packit 1fb8d4
 
Packit 1fb8d4
*/
Packit 1fb8d4
Packit 1fb8d4
#import <sys/socket.h>
Packit 1fb8d4
#import <netinet/in.h>
Packit 1fb8d4
#import <netinet6/in6.h>
Packit 1fb8d4
#import <arpa/inet.h>
Packit 1fb8d4
#import <ifaddrs.h>
Packit 1fb8d4
#import <netdb.h>
Packit 1fb8d4
Packit 1fb8d4
#import <CoreFoundation/CoreFoundation.h>
Packit 1fb8d4
Packit 1fb8d4
#import "Reachability.h"
Packit 1fb8d4
Packit 1fb8d4
#define kShouldPrintReachabilityFlags 1
Packit 1fb8d4
Packit 1fb8d4
static void PrintReachabilityFlags(SCNetworkReachabilityFlags    flags, const char* comment)
Packit 1fb8d4
{
Packit 1fb8d4
#if kShouldPrintReachabilityFlags
Packit 1fb8d4
	
Packit 1fb8d4
    NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsIsWWAN)				  ? 'W' : '-',
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
Packit 1fb8d4
			
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
Packit 1fb8d4
			(flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
Packit 1fb8d4
			comment
Packit 1fb8d4
			);
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
@implementation Reachability
Packit 1fb8d4
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
Packit 1fb8d4
{
Packit 1fb8d4
	#pragma unused (target, flags)
Packit 1fb8d4
	NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
Packit 1fb8d4
	NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
Packit 1fb8d4
Packit 1fb8d4
	//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
Packit 1fb8d4
	// in case someon uses the Reachablity object in a different thread.
Packit 1fb8d4
	NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
Packit 1fb8d4
	
Packit 1fb8d4
	Reachability* noteObject = (Reachability*) info;
Packit 1fb8d4
	// Post a notification to notify the client that the network reachability changed.
Packit 1fb8d4
	[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
Packit 1fb8d4
	
Packit 1fb8d4
	[myPool release];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (BOOL) startNotifier
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL retVal = NO;
Packit 1fb8d4
	SCNetworkReachabilityContext	context = {0, self, NULL, NULL, NULL};
Packit 1fb8d4
	if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
Packit 1fb8d4
	{
Packit 1fb8d4
		if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
Packit 1fb8d4
		{
Packit 1fb8d4
			retVal = YES;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	return retVal;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void) stopNotifier
Packit 1fb8d4
{
Packit 1fb8d4
	if(reachabilityRef!= NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (void) dealloc
Packit 1fb8d4
{
Packit 1fb8d4
	[self stopNotifier];
Packit 1fb8d4
	if(reachabilityRef!= NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		CFRelease(reachabilityRef);
Packit 1fb8d4
	}
Packit 1fb8d4
	[super dealloc];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
Packit 1fb8d4
{
Packit 1fb8d4
	Reachability* retVal = NULL;
Packit 1fb8d4
	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
Packit 1fb8d4
	if(reachability!= NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		retVal= [[[self alloc] init] autorelease];
Packit 1fb8d4
		if(retVal!= NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			retVal->reachabilityRef = reachability;
Packit 1fb8d4
			retVal->localWiFiRef = NO;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	return retVal;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
Packit 1fb8d4
{
Packit 1fb8d4
	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
Packit 1fb8d4
	Reachability* retVal = NULL;
Packit 1fb8d4
	if(reachability!= NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		retVal= [[[self alloc] init] autorelease];
Packit 1fb8d4
		if(retVal!= NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			retVal->reachabilityRef = reachability;
Packit 1fb8d4
			retVal->localWiFiRef = NO;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	return retVal;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
+ (Reachability*) reachabilityForInternetConnection;
Packit 1fb8d4
{
Packit 1fb8d4
	struct sockaddr_in zeroAddress;
Packit 1fb8d4
	bzero(&zeroAddress, sizeof(zeroAddress));
Packit 1fb8d4
	zeroAddress.sin_len = sizeof(zeroAddress);
Packit 1fb8d4
	zeroAddress.sin_family = AF_INET;
Packit 1fb8d4
	return [self reachabilityWithAddress: &zeroAddress];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
+ (Reachability*) reachabilityForLocalWiFi;
Packit 1fb8d4
{
Packit 1fb8d4
	struct sockaddr_in localWifiAddress;
Packit 1fb8d4
	bzero(&localWifiAddress, sizeof(localWifiAddress));
Packit 1fb8d4
	localWifiAddress.sin_len = sizeof(localWifiAddress);
Packit 1fb8d4
	localWifiAddress.sin_family = AF_INET;
Packit 1fb8d4
	// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
Packit 1fb8d4
	localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
Packit 1fb8d4
	Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress];
Packit 1fb8d4
	if(retVal!= NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		retVal->localWiFiRef = YES;
Packit 1fb8d4
	}
Packit 1fb8d4
	return retVal;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#pragma mark Network Flag Handling
Packit 1fb8d4
Packit 1fb8d4
- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
Packit 1fb8d4
{
Packit 1fb8d4
	PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
Packit 1fb8d4
Packit 1fb8d4
	BOOL retVal = NotReachable;
Packit 1fb8d4
	if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
Packit 1fb8d4
	{
Packit 1fb8d4
		retVal = ReachableViaWiFi;	
Packit 1fb8d4
	}
Packit 1fb8d4
	return retVal;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
Packit 1fb8d4
{
Packit 1fb8d4
	PrintReachabilityFlags(flags, "networkStatusForFlags");
Packit 1fb8d4
	if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		// if target host is not reachable
Packit 1fb8d4
		return NotReachable;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	BOOL retVal = NotReachable;
Packit 1fb8d4
	
Packit 1fb8d4
	if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		// if target host is reachable and no connection is required
Packit 1fb8d4
		//  then we'll assume (for now) that your on Wi-Fi
Packit 1fb8d4
		retVal = ReachableViaWiFi;
Packit 1fb8d4
	}
Packit 1fb8d4
	
Packit 1fb8d4
	
Packit 1fb8d4
	if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
Packit 1fb8d4
		(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
Packit 1fb8d4
	{
Packit 1fb8d4
			// ... and the connection is on-demand (or on-traffic) if the
Packit 1fb8d4
			//     calling application is using the CFSocketStream or higher APIs
Packit 1fb8d4
Packit 1fb8d4
			if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				// ... and no [user] intervention is needed
Packit 1fb8d4
				retVal = ReachableViaWiFi;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	
Packit 1fb8d4
	if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
Packit 1fb8d4
	{
Packit 1fb8d4
		// ... but WWAN connections are OK if the calling application
Packit 1fb8d4
		//     is using the CFNetwork (CFSocketStream?) APIs.
Packit 1fb8d4
		retVal = ReachableViaWWAN;
Packit 1fb8d4
	}
Packit 1fb8d4
	return retVal;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (BOOL) connectionRequired;
Packit 1fb8d4
{
Packit 1fb8d4
	NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
Packit 1fb8d4
	SCNetworkReachabilityFlags flags;
Packit 1fb8d4
	if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
Packit 1fb8d4
	{
Packit 1fb8d4
		return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
Packit 1fb8d4
	}
Packit 1fb8d4
	return NO;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
- (NetworkStatus) currentReachabilityStatus
Packit 1fb8d4
{
Packit 1fb8d4
	NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
Packit 1fb8d4
	NetworkStatus retVal = NotReachable;
Packit 1fb8d4
	SCNetworkReachabilityFlags flags;
Packit 1fb8d4
	if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
Packit 1fb8d4
	{
Packit 1fb8d4
		if(localWiFiRef)
Packit 1fb8d4
		{
Packit 1fb8d4
			retVal = [self localWiFiStatusForFlags: flags];
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			retVal = [self networkStatusForFlags: flags];
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	return retVal;
Packit 1fb8d4
}
Packit 1fb8d4
@end