]> git.saurik.com Git - cydia.git/commitdiff
Commit (chpwn): reachability.patch
authorGrant Paul <chpwn@chpwn.com>
Tue, 21 Sep 2010 10:54:30 +0000 (10:54 +0000)
committerJay Freeman (saurik) <saurik@saurik.com>
Thu, 30 Sep 2010 10:42:37 +0000 (10:42 +0000)
Cydia.mm
Reachability.h [new file with mode: 0644]
Reachability.m [new file with mode: 0644]

index e512778a5e8635933deead9597a5b0e38a01a807..ae69e74a6908cd644cbee17fa036ba195574c039 100644 (file)
--- 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 (file)
index 0000000..317982f
--- /dev/null
@@ -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 <Foundation/Foundation.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+
+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 (file)
index 0000000..5ecdcf4
--- /dev/null
@@ -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 <sys/socket.h>
+#import <netinet/in.h>
+#import <netinet6/in6.h>
+#import <arpa/inet.h>
+#import <ifaddrs.h>
+#import <netdb.h>
+
+#import <CoreFoundation/CoreFoundation.h>
+
+#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 <netinet/in.h> 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