Updated Reachability to handle an IP Address or a Host name

Note this does not fix the issue with the status not being correctly
reported for a 3G connection.
This commit is contained in:
Kevin Harwood 2012-03-13 09:12:58 -05:00
parent ac20e02af3
commit d96f8f3fde

View file

@ -208,6 +208,8 @@ static NSString * AFPropertyListStringFromParameters(NSDictionary *parameters) {
#ifdef _SYSTEMCONFIGURATION_H #ifdef _SYSTEMCONFIGURATION_H
- (void)startMonitoringNetworkReachability; - (void)startMonitoringNetworkReachability;
- (void)stopMonitoringNetworkReachability; - (void)stopMonitoringNetworkReachability;
+ (AFNetworkReachabilityStatus)reachabilityStatusForFlags:(SCNetworkReachabilityFlags)flags;
+ (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address;
#endif #endif
@end @end
@ -290,6 +292,76 @@ static NSString * AFPropertyListStringFromParameters(NSDictionary *parameters) {
#ifdef _SYSTEMCONFIGURATION_H #ifdef _SYSTEMCONFIGURATION_H
static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
AFNetworkReachabilityStatus status = [AFHTTPClient reachabilityStatusForFlags:flags];
AFNetworkReachabilityStatusBlock block = (AFNetworkReachabilityStatusBlock)info;
if (block) {
block(status);
}
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingReachabilityDidChangeNotification object:[NSNumber numberWithInt:status]];
}
static const void * AFReachabilityRetainCallback(const void *info) {
return [(AFNetworkReachabilityStatusBlock)info copy];
}
static void AFReachabilityReleaseCallback(const void *info) {
[(AFNetworkReachabilityStatusBlock)info release];
}
- (void)startMonitoringNetworkReachability {
[self stopMonitoringNetworkReachability];
//In order to handle all Reachability cases, we must determine if the Host URL is an IP Address
//or a Host Name. We must then use the appropriate SCNetworkReachabilityCreateWith... function
//based on the result.
NSString * ipMatch = @"^[0-9]{1,3}(.[0-9]{1,3}){3}$";
NSRegularExpression *ipRegex = [NSRegularExpression regularExpressionWithPattern:ipMatch options:NSRegularExpressionCaseInsensitive error:nil];
BOOL isIPAddress = [ipRegex numberOfMatchesInString:[self.baseURL host] options:NSMatchingReportProgress range:NSMakeRange(0, [[self.baseURL host] length])];
if(isIPAddress == YES){
struct sockaddr_in address;
[AFHTTPClient addressFromString:[self.baseURL host] address:&address];
self.networkReachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)&address);
}
else {
self.networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [[self.baseURL host] UTF8String]);
}
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status){
self.networkReachabilityStatus = status;
if (self.networkReachabilityStatusBlock) {
self.networkReachabilityStatusBlock(status);
}
};
SCNetworkReachabilityContext context = {0, callback, AFReachabilityRetainCallback, AFReachabilityReleaseCallback, NULL};
SCNetworkReachabilitySetCallback(self.networkReachability, AFReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes);
if(isIPAddress == YES){
//For SCNetworkReachabilityCreateWithAddress, the callback block is not immediately called.
//In order to duplicate the immediate callback behavior of SCNetworkReachabilityCreateWithName,
//we must pull the current status, and then manually call the block
SCNetworkReachabilityFlags flags;
SCNetworkReachabilityGetFlags(self.networkReachability, &flags);
dispatch_async(dispatch_get_main_queue(), ^{
AFNetworkReachabilityStatus status = [AFHTTPClient reachabilityStatusForFlags:flags];
callback(status);
});
}
}
- (void)stopMonitoringNetworkReachability {
if (_networkReachability) {
SCNetworkReachabilityUnscheduleFromRunLoop(_networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes);
CFRelease(_networkReachability);
}
}
+ (AFNetworkReachabilityStatus)reachabilityStatusForFlags:(SCNetworkReachabilityFlags)flags{
BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
BOOL isNetworkReachable = (isReachable && !needsConnection); BOOL isNetworkReachable = (isReachable && !needsConnection);
@ -315,48 +387,27 @@ static void AFReachabilityCallback(SCNetworkReachabilityRef __unused target, SCN
status = AFNetworkReachabilityStatusReachableViaWiFi; status = AFNetworkReachabilityStatusReachableViaWiFi;
} }
} }
return status;
AFNetworkReachabilityStatusBlock block = (AFNetworkReachabilityStatusBlock)info;
if (block) {
block(status);
} }
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingReachabilityDidChangeNotification object:[NSNumber numberWithBool:status]]; + (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address{
if (!IPAddress || ![IPAddress length]) {
return NO;
} }
static const void * AFReachabilityRetainCallback(const void *info) { memset((char *) address, sizeof(struct sockaddr_in), 0);
return [(AFNetworkReachabilityStatusBlock)info copy]; address->sin_family = AF_INET;
} address->sin_len = sizeof(struct sockaddr_in);
static void AFReachabilityReleaseCallback(const void *info) { int conversionResult = inet_aton([IPAddress UTF8String], &address->sin_addr);
[(AFNetworkReachabilityStatusBlock)info release]; if (conversionResult == 0) {
} return NO;
- (void)startMonitoringNetworkReachability {
[self stopMonitoringNetworkReachability];
self.networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [[self.baseURL host] UTF8String]);
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status){
self.networkReachabilityStatus = status;
if (self.networkReachabilityStatusBlock) {
self.networkReachabilityStatusBlock(status);
}
};
SCNetworkReachabilityContext context = {0, callback, AFReachabilityRetainCallback, AFReachabilityReleaseCallback, NULL};
SCNetworkReachabilitySetCallback(self.networkReachability, AFReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes);
}
- (void)stopMonitoringNetworkReachability {
if (_networkReachability) {
SCNetworkReachabilityUnscheduleFromRunLoop(_networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes);
CFRelease(_networkReachability);
} }
return YES;
} }
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block { - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
self.networkReachabilityStatusBlock = block; self.networkReachabilityStatusBlock = block;
[self startMonitoringNetworkReachability];
} }
#endif #endif