From d56a0c9b9e1f3e1e85c9c04528ae64f5813d3fa6 Mon Sep 17 00:00:00 2001 From: Grant Paul Date: Tue, 21 Sep 2010 10:54:30 +0000 Subject: [PATCH] Commit (chpwn): reachability.patch --- Cydia.mm | 53 +++++++--- Reachability.h | 88 ++++++++++++++++ Reachability.m | 273 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 397 insertions(+), 17 deletions(-) create mode 100644 Reachability.h create mode 100644 Reachability.m diff --git a/Cydia.mm b/Cydia.mm index e512778a..ae69e74a 100644 --- a/Cydia.mm +++ b/Cydia.mm @@ -120,6 +120,9 @@ extern "C" { #import "UICaboodle/ResetView.h" #import "substrate.h" + +// Apple's sample Reachability code, ASPL licensed. +#import "Reachability.h" /* }}} */ /* Header Fixes and Updates {{{ */ @@ -7616,6 +7619,8 @@ typedef enum { #if RecyclePackageViews NSMutableArray *details_; #endif + + bool loaded_; } - (UIViewController *) _pageForURL:(NSURL *)url withClass:(Class)_class; @@ -7714,12 +7719,40 @@ static _finline void _setHomePage(Cydia *self) { return -1; } +- (void) _refreshIfPossible { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + Reachability* reachability = [Reachability reachabilityWithHostName:@"cydia.saurik.com"]; + NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus]; + + if (loaded_ || ManualRefresh || remoteHostStatus == NotReachable) loaded: + [self performSelectorOnMainThread:@selector(_loaded) withObject:nil waitUntilDone:NO]; + else { + loaded_ = true; + + NSDate *update([Metadata_ objectForKey:@"LastUpdate"]); + + if (update != nil) { + NSTimeInterval interval([update timeIntervalSinceNow]); + if (interval <= 0 && interval > -(15*60)) + goto loaded; + } + + [tabbar_ performSelectorOnMainThread:@selector(setUpdate:) withObject:update waitUntilDone:NO]; + } + + [pool release]; +} + +- (void) refreshIfPossible { + [NSThread detachNewThreadSelector:@selector(_refreshIfPossible) toTarget:self withObject:nil]; +} + - (void) _reloadData { UIView *block(); - static bool loaded(false); UIProgressHUD *hud([self addProgressHUD]); - [hud setText:(loaded ? UCLocalize("RELOADING_DATA") : UCLocalize("LOADING_DATA"))]; + [hud setText:(loaded_ ? UCLocalize("RELOADING_DATA") : UCLocalize("LOADING_DATA"))]; [database_ yieldToSelector:@selector(reloadData) withObject:nil]; _trace(); @@ -7763,21 +7796,7 @@ static _finline void _setHomePage(Cydia *self) { [self _updateData]; - if (loaded || ManualRefresh) loaded: - [self _loaded]; - else { - loaded = true; - - NSDate *update([Metadata_ objectForKey:@"LastUpdate"]); - - if (update != nil) { - NSTimeInterval interval([update timeIntervalSinceNow]); - if (interval <= 0 && interval > -(15*60)) - goto loaded; - } - - [tabbar_ setUpdate:update]; - } + [self refreshIfPossible]; } - (void) updateData { diff --git a/Reachability.h b/Reachability.h new file mode 100644 index 00000000..317982fb --- /dev/null +++ b/Reachability.h @@ -0,0 +1,88 @@ +/* + + File: Reachability.h + Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + + Version: 2.2 + + 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) 2010 Apple Inc. All Rights Reserved. + +*/ + + +#import +#import + +typedef enum { + NotReachable = 0, + ReachableViaWiFi, + ReachableViaWWAN +} NetworkStatus; +#define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification" + +@interface Reachability: NSObject +{ + BOOL localWiFiRef; + SCNetworkReachabilityRef reachabilityRef; +} + +//reachabilityWithHostName- Use to check the reachability of a particular host name. ++ (Reachability*) reachabilityWithHostName: (NSString*) hostName; + +//reachabilityWithAddress- Use to check the reachability of a particular IP address. ++ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress; + +//reachabilityForInternetConnection- checks whether the default route is available. +// Should be used by applications that do not connect to a particular host ++ (Reachability*) reachabilityForInternetConnection; + +//reachabilityForLocalWiFi- checks whether a local wifi connection is available. ++ (Reachability*) reachabilityForLocalWiFi; + +//Start listening for reachability notifications on the current run loop +- (BOOL) startNotifier; +- (void) stopNotifier; + +- (NetworkStatus) currentReachabilityStatus; +//WWAN may be available, but not active until a connection has been established. +//WiFi may require a connection for VPN on Demand. +- (BOOL) connectionRequired; +@end + + diff --git a/Reachability.m b/Reachability.m new file mode 100644 index 00000000..5ecdcf4e --- /dev/null +++ b/Reachability.m @@ -0,0 +1,273 @@ +/* + + File: Reachability.m + Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + + Version: 2.2 + + 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) 2010 Apple Inc. All Rights Reserved. + +*/ + +#import +#import +#import +#import +#import +#import + +#import + +#import "Reachability.h" + +#define kShouldPrintReachabilityFlags 1 + +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 +} + + +@implementation Reachability +static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) +{ + #pragma unused (target, flags) + NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); + NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback"); + + //We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively + // in case someon uses the Reachablity object in a different thread. + NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init]; + + Reachability* noteObject = (Reachability*) info; + // Post a notification to notify the client that the network reachability changed. + [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject]; + + [myPool release]; +} + +- (BOOL) startNotifier +{ + BOOL retVal = NO; + SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL}; + if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) + { + if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) + { + retVal = YES; + } + } + return retVal; +} + +- (void) stopNotifier +{ + if(reachabilityRef!= NULL) + { + SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + } +} + +- (void) dealloc +{ + [self stopNotifier]; + if(reachabilityRef!= NULL) + { + CFRelease(reachabilityRef); + } + [super dealloc]; +} + ++ (Reachability*) reachabilityWithHostName: (NSString*) hostName; +{ + Reachability* retVal = NULL; + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); + if(reachability!= NULL) + { + retVal= [[[self alloc] init] autorelease]; + if(retVal!= NULL) + { + retVal->reachabilityRef = reachability; + retVal->localWiFiRef = NO; + } + } + return retVal; +} + ++ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress; +{ + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); + Reachability* retVal = NULL; + if(reachability!= NULL) + { + retVal= [[[self alloc] init] autorelease]; + if(retVal!= NULL) + { + retVal->reachabilityRef = reachability; + retVal->localWiFiRef = NO; + } + } + return retVal; +} + ++ (Reachability*) reachabilityForInternetConnection; +{ + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + return [self reachabilityWithAddress: &zeroAddress]; +} + ++ (Reachability*) reachabilityForLocalWiFi; +{ + struct sockaddr_in localWifiAddress; + bzero(&localWifiAddress, sizeof(localWifiAddress)); + localWifiAddress.sin_len = sizeof(localWifiAddress); + localWifiAddress.sin_family = AF_INET; + // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 + localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); + Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress]; + if(retVal!= NULL) + { + retVal->localWiFiRef = YES; + } + return retVal; +} + +#pragma mark Network Flag Handling + +- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags +{ + PrintReachabilityFlags(flags, "localWiFiStatusForFlags"); + + BOOL retVal = NotReachable; + if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) + { + retVal = ReachableViaWiFi; + } + return retVal; +} + +- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags +{ + PrintReachabilityFlags(flags, "networkStatusForFlags"); + if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) + { + // if target host is not reachable + return NotReachable; + } + + BOOL retVal = NotReachable; + + if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) + { + // if target host is reachable and no connection is required + // then we'll assume (for now) that your on Wi-Fi + retVal = 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 + retVal = ReachableViaWiFi; + } + } + + if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) + { + // ... but WWAN connections are OK if the calling application + // is using the CFNetwork (CFSocketStream?) APIs. + retVal = ReachableViaWWAN; + } + return retVal; +} + +- (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 retVal = NotReachable; + SCNetworkReachabilityFlags flags; + if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + if(localWiFiRef) + { + retVal = [self localWiFiStatusForFlags: flags]; + } + else + { + retVal = [self networkStatusForFlags: flags]; + } + } + return retVal; +} +@end -- 2.45.2