Blame client/iOS/Misc/Reachability.m

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