Files
Jot/Carthage/Checkouts/PromiseKit/Extensions/SystemConfiguration/Sources/SCNetworkReachability+AnyPromise.m
James Griffin be7b6b5881 Add PromiseKit dependency
- Added PromiseKit dependency
2018-11-15 22:12:39 -04:00

117 lines
3.2 KiB
Objective-C

#import <arpa/inet.h>
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <PromiseKit/AnyPromise.h>
#import <sys/socket.h>
#import <SystemConfiguration/SystemConfiguration.h>
@interface JTSReachability: NSObject {
@public
PMKResolver resolve;
id retainCycle;
}
- (BOOL)reachable;
- (void)start;
@end
AnyPromise *SCNetworkReachability() {
JTSReachability *reach = [JTSReachability new];
if (reach.reachable)
return [AnyPromise promiseWithValue:nil];
reach->retainCycle = reach;
[reach start];
return [[AnyPromise alloc] initWithResolver:&reach->resolve];
}
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
JTSReachability *reachability = (__bridge JTSReachability *)info;
if (reachability.reachable) {
reachability->resolve(nil);
reachability->retainCycle = nil;
}
}
@implementation JTSReachability {
SCNetworkReachabilityRef reachabilityRef;
}
- (instancetype)init {
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
reachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress);
return self;
}
- (void)start {
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
- (void)dealloc {
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFRelease(reachabilityRef);
}
- (BOOL)reachable {
SCNetworkReachabilityFlags flags;
if (!SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
return NO;
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
return NO;
BOOL returnValue = NO;
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 = YES;
}
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 = YES;
}
}
#if TARGET_OS_IPHONE
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
/*
... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
*/
if (flags & kSCNetworkReachabilityFlagsConnectionRequired) {
returnValue = NO;
} else {
returnValue = YES;
}
}
#endif
return returnValue;
}
@end