123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- /*
- File: Reachability.m
- Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
- Version: 3.0
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
- 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 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.
- Copyright (C) 2013 Apple Inc. All Rights Reserved.
- */
- #import <arpa/inet.h>
- #import <ifaddrs.h>
- #import <netdb.h>
- #import <sys/socket.h>
- #import <CoreFoundation/CoreFoundation.h>
- #import "Reachability.h"
- NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
- #pragma mark - Supporting functions
- #ifndef NDEBUG
- #define kShouldPrintReachabilityFlags 1
- #else
- #define kShouldPrintReachabilityFlags 0
- #endif
- static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
- {
- #if kShouldPrintReachabilityFlags
- NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
- (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
- (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
- (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
- (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
- (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
- (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
- (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
- (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
- (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
- comment
- );
- #endif
- }
- static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
- {
- #pragma unused (target, flags)
- NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
- NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
- Reachability* noteObject = (__bridge Reachability *)info;
- // Post a notification to notify the client that the network reachability changed.
- [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
- }
- #pragma mark - Reachability implementation
- @implementation Reachability
- {
- BOOL localWiFiRef;
- SCNetworkReachabilityRef reachabilityRef;
- }
- + (instancetype)reachabilityWithHostName:(NSString *)hostName;
- {
- Reachability* returnValue = NULL;
- SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
- if (reachability != NULL)
- {
- returnValue= [[Reachability alloc] init];
- if (returnValue != NULL)
- {
- returnValue->reachabilityRef = reachability;
- returnValue->localWiFiRef = NO;
- }
- }
- return returnValue;
- }
- + (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;
- {
- SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);
- Reachability* returnValue = NULL;
- if (reachability != NULL)
- {
- returnValue = [[Reachability alloc] init];
- if (returnValue != NULL)
- {
- returnValue->reachabilityRef = reachability;
- returnValue->localWiFiRef = NO;
- }
- }
- return returnValue;
- }
- + (instancetype)reachabilityForInternetConnection;
- {
- struct sockaddr_in zeroAddress;
- bzero(&zeroAddress, sizeof(zeroAddress));
- zeroAddress.sin_len = sizeof(zeroAddress);
- zeroAddress.sin_family = AF_INET;
- return [self reachabilityWithAddress:&zeroAddress];
- }
- + (instancetype)reachabilityForLocalWiFi;
- {
- struct sockaddr_in localWifiAddress;
- bzero(&localWifiAddress, sizeof(localWifiAddress));
- localWifiAddress.sin_len = sizeof(localWifiAddress);
- localWifiAddress.sin_family = AF_INET;
- // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0.
- localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
- Reachability* returnValue = [self reachabilityWithAddress: &localWifiAddress];
- if (returnValue != NULL)
- {
- returnValue->localWiFiRef = YES;
- }
- return returnValue;
- }
- #pragma mark - Start and stop notifier
- - (BOOL)startNotifier
- {
- BOOL returnValue = NO;
- SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
- if (SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
- {
- if (SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
- {
- returnValue = YES;
- }
- }
- return returnValue;
- }
- - (void)stopNotifier
- {
- if (reachabilityRef != NULL)
- {
- SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- }
- }
- - (void)dealloc
- {
- [self stopNotifier];
- if (reachabilityRef != NULL)
- {
- CFRelease(reachabilityRef);
- }
- }
- #pragma mark - Network Flag Handling
- - (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags
- {
- PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
- BOOL returnValue = NotReachable;
- if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
- {
- returnValue = ReachableViaWiFi;
- }
- return returnValue;
- }
- - (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
- {
- PrintReachabilityFlags(flags, "networkStatusForFlags");
- if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
- {
- // The target host is not reachable.
- return NotReachable;
- }
- BOOL returnValue = NotReachable;
- if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
- {
- /*
- If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
- */
- returnValue = ReachableViaWiFi;
- }
- if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
- (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
- {
- /*
- ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
- */
- if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
- {
- /*
- ... and no [user] intervention is needed...
- */
- returnValue = ReachableViaWiFi;
- }
- }
- if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
- {
- /*
- ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
- */
- returnValue = ReachableViaWWAN;
- }
- return returnValue;
- }
- - (BOOL)connectionRequired
- {
- NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
- SCNetworkReachabilityFlags flags;
- if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
- {
- return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
- }
- return NO;
- }
- - (NetworkStatus)currentReachabilityStatus
- {
- NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
- NetworkStatus returnValue = NotReachable;
- SCNetworkReachabilityFlags flags;
- if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
- {
- if (localWiFiRef)
- {
- returnValue = [self localWiFiStatusForFlags:flags];
- }
- else
- {
- returnValue = [self networkStatusForFlags:flags];
- }
- }
- return returnValue;
- }
- @end
|