Browse Source

Merge pull request #326 from adam-p/master

Strip simulator slices
Adam Pritchard 9 years ago
parent
commit
c56566bb43

+ 4 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel.xcodeproj/project.pbxproj

@@ -15,6 +15,7 @@
 		6685BDCD1E2E88A200F0E414 /* Psi-meta.h in Headers */ = {isa = PBXBuildFile; fileRef = 6685BDCC1E2E88A200F0E414 /* Psi-meta.h */; };
 		6685BDD41E2EBB1000F0E414 /* GoPsi.objc.h in Headers */ = {isa = PBXBuildFile; fileRef = 6685BDD21E2EBB1000F0E414 /* GoPsi.objc.h */; };
 		6685BDD51E2EBB1000F0E414 /* Universe.objc.h in Headers */ = {isa = PBXBuildFile; fileRef = 6685BDD31E2EBB1000F0E414 /* Universe.objc.h */; };
+		6685BDD91E300AC200F0E414 /* strip-frameworks.sh in Resources */ = {isa = PBXBuildFile; fileRef = 6685BDD81E300AC200F0E414 /* strip-frameworks.sh */; };
 		66BDB02A1DA6BFCC0079384C /* PsiphonTunnel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66BDB0201DA6BFCC0079384C /* PsiphonTunnel.framework */; };
 		66BDB02F1DA6BFCC0079384C /* PsiphonTunnelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 66BDB02E1DA6BFCC0079384C /* PsiphonTunnelTests.m */; };
 		66BDB0311DA6BFCC0079384C /* PsiphonTunnel.h in Headers */ = {isa = PBXBuildFile; fileRef = 66BDB0231DA6BFCC0079384C /* PsiphonTunnel.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -68,6 +69,7 @@
 		6685BDCC1E2E88A200F0E414 /* Psi-meta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Psi-meta.h"; path = "PsiphonTunnel/Psi-meta.h"; sourceTree = "<group>"; };
 		6685BDD21E2EBB1000F0E414 /* GoPsi.objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GoPsi.objc.h; path = PsiphonTunnel/Psi.framework/Versions/A/Headers/GoPsi.objc.h; sourceTree = "<group>"; };
 		6685BDD31E2EBB1000F0E414 /* Universe.objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Universe.objc.h; path = PsiphonTunnel/Psi.framework/Versions/A/Headers/Universe.objc.h; sourceTree = "<group>"; };
+		6685BDD81E300AC200F0E414 /* strip-frameworks.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = "strip-frameworks.sh"; path = "scripts/strip-frameworks.sh"; sourceTree = "<group>"; };
 		66BDB0201DA6BFCC0079384C /* PsiphonTunnel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PsiphonTunnel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		66BDB0231DA6BFCC0079384C /* PsiphonTunnel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PsiphonTunnel.h; sourceTree = "<group>"; };
 		66BDB0241DA6BFCC0079384C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -179,6 +181,7 @@
 		66BDB03C1DA6C7940079384C /* Resources */ = {
 			isa = PBXGroup;
 			children = (
+				6685BDD81E300AC200F0E414 /* strip-frameworks.sh */,
 				66BDB03D1DA6C79E0079384C /* rootCAs.txt */,
 			);
 			name = Resources;
@@ -316,6 +319,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				66BDB03E1DA6C79E0079384C /* rootCAs.txt in Resources */,
+				6685BDD91E300AC200F0E414 /* strip-frameworks.sh in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 5 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Reachability/README.md

@@ -0,0 +1,5 @@
+# Reachability
+
+This code is from: 
+
+https://developer.apple.com/library/content/samplecode/Reachability/Introduction/Intro.html

+ 40 - 78
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Reachability/Reachability.h

@@ -1,102 +1,64 @@
 /*
- Copyright (c) 2011, Tony Million.
- All rights reserved.
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sample’s licensing information
  
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 
- 1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- 
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- 
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
+ Abstract:
+ Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
  */
 
 #import <Foundation/Foundation.h>
 #import <SystemConfiguration/SystemConfiguration.h>
+#import <netinet/in.h>
 
-//! Project version number for MacOSReachability.
-FOUNDATION_EXPORT double ReachabilityVersionNumber;
-
-//! Project version string for MacOSReachability.
-FOUNDATION_EXPORT const unsigned char ReachabilityVersionString[];
 
-/**
- * Create NS_ENUM macro if it does not exist on the targeted version of iOS or OS X.
- *
- * @see http://nshipster.com/ns_enum-ns_options/
- **/
-#ifndef NS_ENUM
-#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
-#endif
+typedef enum : NSInteger {
+	NotReachable = 0,
+	ReachableViaWiFi,
+	ReachableViaWWAN
+} NetworkStatus;
 
-extern NSString *const kReachabilityChangedNotification;
+#pragma mark IPv6 Support
+//Reachability fully support IPv6.  For full details, see ReadMe.md.
 
-typedef NS_ENUM(NSInteger, NetworkStatus) {
-    // Apple NetworkStatus Compatible Names.
-    NotReachable = 0,
-    ReachableViaWiFi = 2,
-    ReachableViaWWAN = 1
-};
 
-@class Reachability;
-
-typedef void (^NetworkReachable)(Reachability * reachability);
-typedef void (^NetworkUnreachable)(Reachability * reachability);
-typedef void (^NetworkReachability)(Reachability * reachability, SCNetworkConnectionFlags flags);
+extern NSString *kReachabilityChangedNotification;
 
 
 @interface Reachability : NSObject
 
-@property (nonatomic, copy) NetworkReachable    reachableBlock;
-@property (nonatomic, copy) NetworkUnreachable  unreachableBlock;
-@property (nonatomic, copy) NetworkReachability reachabilityBlock;
-
-@property (nonatomic, assign) BOOL reachableOnWWAN;
+/*!
+ * Use to check the reachability of a given host name.
+ */
++ (instancetype)reachabilityWithHostName:(NSString *)hostName;
 
+/*!
+ * Use to check the reachability of a given IP address.
+ */
++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
 
-+(instancetype)reachabilityWithHostname:(NSString*)hostname;
-// This is identical to the function above, but is here to maintain
-//compatibility with Apples original code. (see .m)
-+(instancetype)reachabilityWithHostName:(NSString*)hostname;
-+(instancetype)reachabilityForInternetConnection;
-+(instancetype)reachabilityWithAddress:(void *)hostAddress;
-+(instancetype)reachabilityForLocalWiFi;
+/*!
+ * Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
+ */
++ (instancetype)reachabilityForInternetConnection;
 
--(instancetype)initWithReachabilityRef:(SCNetworkReachabilityRef)ref;
 
--(BOOL)startNotifier;
--(void)stopNotifier;
+#pragma mark reachabilityForLocalWiFi
+//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
+//+ (instancetype)reachabilityForLocalWiFi;
 
--(BOOL)isReachable;
--(BOOL)isReachableViaWWAN;
--(BOOL)isReachableViaWiFi;
+/*!
+ * Start listening for reachability notifications on the current run loop.
+ */
+- (BOOL)startNotifier;
+- (void)stopNotifier;
 
-// WWAN may be available, but not active until a connection has been established.
-// WiFi may require a connection for VPN on Demand.
--(BOOL)isConnectionRequired; // Identical DDG variant.
--(BOOL)connectionRequired; // Apple's routine.
-// Dynamic, on demand connection?
--(BOOL)isConnectionOnDemand;
-// Is user intervention required?
--(BOOL)isInterventionRequired;
+- (NetworkStatus)currentReachabilityStatus;
 
--(NetworkStatus)currentReachabilityStatus;
--(SCNetworkReachabilityFlags)reachabilityFlags;
--(NSString*)currentReachabilityString;
--(NSString*)currentReachabilityFlags;
+/*!
+ * 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
+
+

+ 160 - 399
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Reachability/Reachability.m

@@ -1,481 +1,242 @@
 /*
- Copyright (c) 2011, Tony Million.
- All rights reserved.
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sample’s licensing information
  
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 
- 1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- 
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- 
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
+ Abstract:
+ Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
  */
 
-#import "Reachability.h"
-
-#import <sys/socket.h>
-#import <netinet/in.h>
-#import <netinet6/in6.h>
 #import <arpa/inet.h>
 #import <ifaddrs.h>
 #import <netdb.h>
+#import <sys/socket.h>
+#import <netinet/in.h>
 
+#import <CoreFoundation/CoreFoundation.h>
 
-NSString *const kReachabilityChangedNotification = @"kReachabilityChangedNotification";
+#import "Reachability.h"
 
+#pragma mark IPv6 Support
+//Reachability fully support IPv6.  For full details, see ReadMe.md.
 
-@interface Reachability ()
 
-@property (nonatomic, assign) SCNetworkReachabilityRef  reachabilityRef;
-@property (nonatomic, strong) dispatch_queue_t          reachabilitySerialQueue;
-@property (nonatomic, strong) id                        reachabilityObject;
+NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
 
--(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags;
--(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags;
 
-@end
+#pragma mark - Supporting functions
 
+#define kShouldPrintReachabilityFlags 1
 
-static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags)
+static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
 {
-    return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c",
-#if	TARGET_OS_IPHONE
-            (flags & kSCNetworkReachabilityFlagsIsWWAN)               ? 'W' : '-',
-#else
-            'X',
-#endif
-            (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
-            (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
-            (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
-            (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
-            (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
-            (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
-            (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
-            (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-'];
-}
+#if kShouldPrintReachabilityFlags
 
-// Start listening for reachability notifications on the current run loop
-static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
-{
-#pragma unused (target)
-    
-    Reachability *reachability = ((__bridge Reachability*)info);
-    
-    // We probably don't need an autoreleasepool here, as GCD docs state each queue has its own autorelease pool,
-    // but what the heck eh?
-    @autoreleasepool
-    {
-        [reachability reachabilityChanged:flags];
-    }
-}
+    NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
+          (flags & kSCNetworkReachabilityFlagsIsWWAN)				? 'W' : '-',
+          (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
 
-
-@implementation Reachability
-
-#pragma mark - Class Constructor Methods
-
-+(instancetype)reachabilityWithHostName:(NSString*)hostname
-{
-    return [Reachability reachabilityWithHostname:hostname];
+          (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
+          (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
+          (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
+          (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
+          comment
+          );
+#endif
 }
 
-+(instancetype)reachabilityWithHostname:(NSString*)hostname
-{
-    SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
-    if (ref)
-    {
-        id reachability = [[self alloc] initWithReachabilityRef:ref];
-        
-        CFRelease(ref);
-        
-        return reachability;
-    }
-    
-    return nil;
-}
 
-+(instancetype)reachabilityWithAddress:(void *)hostAddress
+static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
 {
-    SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
-    if (ref)
-    {
-        id reachability = [[self alloc] initWithReachabilityRef:ref];
-        
-        CFRelease(ref);
-        
-        return reachability;
-    }
-    
-    return nil;
-}
+#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");
 
-+(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);
-    
-    return [self reachabilityWithAddress:&localWifiAddress];
+    Reachability* noteObject = (__bridge Reachability *)info;
+    // Post a notification to notify the client that the network reachability changed.
+    [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
 }
 
 
-// Initialization methods
+#pragma mark - Reachability implementation
 
--(instancetype)initWithReachabilityRef:(SCNetworkReachabilityRef)ref
+@implementation Reachability
 {
-    self = [super init];
-    if (self != nil)
-    {
-        self.reachableOnWWAN = YES;
-        self.reachabilityRef = ref;
-        
-        CFRetain(self.reachabilityRef);
-        
-        // We need to create a serial queue.
-        // We allocate this once for the lifetime of the notifier.
-        
-        self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL);
-    }
-    
-    return self;
+	SCNetworkReachabilityRef _reachabilityRef;
 }
 
--(void)dealloc
++ (instancetype)reachabilityWithHostName:(NSString *)hostName
 {
-    [self stopNotifier];
-    
-    if(self.reachabilityRef)
-    {
-        CFRelease(self.reachabilityRef);
-        self.reachabilityRef = nil;
-    }
-    
-    self.reachableBlock          = nil;
-    self.unreachableBlock        = nil;
-    self.reachabilityBlock       = nil;
-    self.reachabilitySerialQueue = nil;
+	Reachability* returnValue = NULL;
+	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
+	if (reachability != NULL)
+	{
+		returnValue= [[self alloc] init];
+		if (returnValue != NULL)
+		{
+			returnValue->_reachabilityRef = reachability;
+		}
+        else {
+            CFRelease(reachability);
+        }
+	}
+	return returnValue;
 }
 
-#pragma mark - Notifier Methods
 
-// Notifier
-// NOTE: This uses GCD to trigger the blocks - they *WILL NOT* be called on THE MAIN THREAD
-// - In other words DO NOT DO ANY UI UPDATES IN THE BLOCKS.
-//   INSTEAD USE dispatch_async(dispatch_get_main_queue(), ^{UISTUFF}) (or dispatch_sync if you want)
-
--(BOOL)startNotifier
++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
 {
-    // allow start notifier to be called multiple times
-    if(self.reachabilityObject && (self.reachabilityObject == self))
-    {
-        return YES;
-    }
-    
-    
-    SCNetworkReachabilityContext    context = { 0, NULL, NULL, NULL, NULL };
-    context.info = (__bridge void *)self;
-    
-    if(SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context))
-    {
-        // Set it as our reachability queue, which will retain the queue
-        if(SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue))
-        {
-            // this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves
-            // woah
-            self.reachabilityObject = self;
-            return YES;
-        }
-        else
-        {
-#ifdef DEBUG
-            NSLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError()));
-#endif
-            
-            // UH OH - FAILURE - stop any callbacks!
-            SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL);
+	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
+
+	Reachability* returnValue = NULL;
+
+	if (reachability != NULL)
+	{
+		returnValue = [[self alloc] init];
+		if (returnValue != NULL)
+		{
+			returnValue->_reachabilityRef = reachability;
+		}
+        else {
+            CFRelease(reachability);
         }
-    }
-    else
-    {
-#ifdef DEBUG
-        NSLog(@"SCNetworkReachabilitySetCallback() failed: %s", SCErrorString(SCError()));
-#endif
-    }
-    
-    // if we get here we fail at the internet
-    self.reachabilityObject = nil;
-    return NO;
+	}
+	return returnValue;
 }
 
--(void)stopNotifier
+
++ (instancetype)reachabilityForInternetConnection
 {
-    // First stop, any callbacks!
-    SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL);
+	struct sockaddr_in zeroAddress;
+	bzero(&zeroAddress, sizeof(zeroAddress));
+	zeroAddress.sin_len = sizeof(zeroAddress);
+	zeroAddress.sin_family = AF_INET;
     
-    // Unregister target from the GCD serial dispatch queue.
-    SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, NULL);
-    
-    self.reachabilityObject = nil;
+    return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
 }
 
-#pragma mark - reachability tests
+#pragma mark reachabilityForLocalWiFi
+//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
+//+ (instancetype)reachabilityForLocalWiFi
 
-// This is for the case where you flick the airplane mode;
-// you end up getting something like this:
-//Reachability: WR ct-----
-//Reachability: -- -------
-//Reachability: WR ct-----
-//Reachability: -- -------
-// We treat this as 4 UNREACHABLE triggers - really apple should do better than this
 
-#define testcase (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection)
 
--(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags
-{
-    BOOL connectionUP = YES;
-    
-    if(!(flags & kSCNetworkReachabilityFlagsReachable))
-        connectionUP = NO;
-    
-    if( (flags & testcase) == testcase )
-        connectionUP = NO;
-    
-#if	TARGET_OS_IPHONE
-    if(flags & kSCNetworkReachabilityFlagsIsWWAN)
-    {
-        // We're on 3G.
-        if(!self.reachableOnWWAN)
-        {
-            // We don't want to connect when on 3G.
-            connectionUP = NO;
-        }
-    }
-#endif
-    
-    return connectionUP;
-}
+#pragma mark - Start and stop notifier
 
--(BOOL)isReachable
+- (BOOL)startNotifier
 {
-    SCNetworkReachabilityFlags flags;
-    
-    if(!SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
-        return NO;
-    
-    return [self isReachableWithFlags:flags];
-}
+	BOOL returnValue = NO;
+	SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
 
--(BOOL)isReachableViaWWAN
-{
-#if	TARGET_OS_IPHONE
+	if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
+	{
+		if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
+		{
+			returnValue = YES;
+		}
+	}
     
-    SCNetworkReachabilityFlags flags = 0;
-    
-    if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
-    {
-        // Check we're REACHABLE
-        if(flags & kSCNetworkReachabilityFlagsReachable)
-        {
-            // Now, check we're on WWAN
-            if(flags & kSCNetworkReachabilityFlagsIsWWAN)
-            {
-                return YES;
-            }
-        }
-    }
-#endif
-    
-    return NO;
+	return returnValue;
 }
 
--(BOOL)isReachableViaWiFi
+
+- (void)stopNotifier
 {
-    SCNetworkReachabilityFlags flags = 0;
-    
-    if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
-    {
-        // Check we're reachable
-        if((flags & kSCNetworkReachabilityFlagsReachable))
-        {
-#if	TARGET_OS_IPHONE
-            // Check we're NOT on WWAN
-            if((flags & kSCNetworkReachabilityFlagsIsWWAN))
-            {
-                return NO;
-            }
-#endif
-            return YES;
-        }
-    }
-    
-    return NO;
+	if (_reachabilityRef != NULL)
+	{
+		SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+	}
 }
 
 
-// WWAN may be available, but not active until a connection has been established.
-// WiFi may require a connection for VPN on Demand.
--(BOOL)isConnectionRequired
+- (void)dealloc
 {
-    return [self connectionRequired];
+	[self stopNotifier];
+	if (_reachabilityRef != NULL)
+	{
+		CFRelease(_reachabilityRef);
+	}
 }
 
--(BOOL)connectionRequired
-{
-    SCNetworkReachabilityFlags flags;
-    
-    if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
-    {
-        return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
-    }
-    
-    return NO;
-}
 
-// Dynamic, on demand connection?
--(BOOL)isConnectionOnDemand
-{
-    SCNetworkReachabilityFlags flags;
-    
-    if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
-    {
-        return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
-                (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand)));
-    }
-    
-    return NO;
-}
+#pragma mark - Network Flag Handling
 
-// Is user intervention required?
--(BOOL)isInterventionRequired
+- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
 {
-    SCNetworkReachabilityFlags flags;
-    
-    if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
-    {
-        return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
-                (flags & kSCNetworkReachabilityFlagsInterventionRequired));
-    }
-    
-    return NO;
-}
+	PrintReachabilityFlags(flags, "networkStatusForFlags");
+	if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
+	{
+		// The target host is not reachable.
+		return NotReachable;
+	}
 
+    NetworkStatus returnValue = NotReachable;
 
-#pragma mark - reachability status stuff
+	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;
+	}
 
--(NetworkStatus)currentReachabilityStatus
-{
-    if([self isReachable])
-    {
-        if([self isReachableViaWiFi])
-            return ReachableViaWiFi;
-        
-#if	TARGET_OS_IPHONE
-        return ReachableViaWWAN;
-#endif
-    }
-    
-    return NotReachable;
-}
+	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...
+         */
 
--(SCNetworkReachabilityFlags)reachabilityFlags
-{
-    SCNetworkReachabilityFlags flags = 0;
-    
-    if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
-    {
-        return flags;
+        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
+        {
+            /*
+             ... and no [user] intervention is needed...
+             */
+            returnValue = ReachableViaWiFi;
+        }
     }
-    
-    return 0;
-}
 
--(NSString*)currentReachabilityString
-{
-    NetworkStatus temp = [self currentReachabilityStatus];
+	if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
+	{
+		/*
+         ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
+         */
+		returnValue = ReachableViaWWAN;
+	}
     
-    if(temp == ReachableViaWWAN)
-    {
-        // Updated for the fact that we have CDMA phones now!
-        return NSLocalizedString(@"Cellular", @"");
-    }
-    if (temp == ReachableViaWiFi)
-    {
-        return NSLocalizedString(@"WiFi", @"");
-    }
-    
-    return NSLocalizedString(@"No Connection", @"");
+	return returnValue;
 }
 
--(NSString*)currentReachabilityFlags
+
+- (BOOL)connectionRequired
 {
-    return reachabilityFlags([self reachabilityFlags]);
+	NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
+	SCNetworkReachabilityFlags flags;
+
+	if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
+	{
+		return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
+	}
+
+    return NO;
 }
 
-#pragma mark - Callback function calls this method
 
--(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags
+- (NetworkStatus)currentReachabilityStatus
 {
-    if([self isReachableWithFlags:flags])
-    {
-        if(self.reachableBlock)
-        {
-            self.reachableBlock(self);
-        }
-    }
-    else
-    {
-        if(self.unreachableBlock)
-        {
-            self.unreachableBlock(self);
-        }
-    }
+	NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
+	NetworkStatus returnValue = NotReachable;
+	SCNetworkReachabilityFlags flags;
     
-    if(self.reachabilityBlock)
-    {
-        self.reachabilityBlock(self, flags);
-    }
+	if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
+	{
+        returnValue = [self networkStatusForFlags:flags];
+	}
     
-    // this makes sure the change notification happens on the MAIN THREAD
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification
-                                                            object:self];
-    });
+	return returnValue;
 }
 
-#pragma mark - Debug Description
-
-- (NSString *) description
-{
-    NSString *description = [NSString stringWithFormat:@"<%@: %#x (%@)>",
-                             NSStringFromClass([self class]), (unsigned int) self, [self currentReachabilityFlags]];
-    return description;
-}
 
 @end

+ 72 - 0
MobileLibrary/iOS/PsiphonTunnel/scripts/strip-frameworks.sh

@@ -0,0 +1,72 @@
+################################################################################
+#
+# Copyright 2015 Realm Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+################################################################################
+
+# This script strips all non-valid architectures from dynamic libraries in
+# the application's `Frameworks` directory.
+#
+# The following environment variables are required:
+#
+# BUILT_PRODUCTS_DIR
+# FRAMEWORKS_FOLDER_PATH
+# VALID_ARCHS
+# EXPANDED_CODE_SIGN_IDENTITY
+
+
+# Signs a framework with the provided identity
+code_sign() {
+  # Use the current code_sign_identitiy
+  echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
+  echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements $1"
+  /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1"
+}
+
+# Set working directory to product’s embedded frameworks 
+cd "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+if [ "$ACTION" = "install" ]; then
+  echo "Copy .bcsymbolmap files to .xcarchive"
+  find . -name '*.bcsymbolmap' -type f -exec mv {} "${CONFIGURATION_BUILD_DIR}" \;
+else
+  # Delete *.bcsymbolmap files from framework bundle unless archiving
+  find . -name '*.bcsymbolmap' -type f -exec rm -rf "{}" +\;
+fi
+
+echo "Stripping frameworks"
+
+for file in $(find . -type f -perm +111); do
+  # Skip non-dynamic libraries
+  if ! [[ "$(file "$file")" == *"dynamically linked shared library"* ]]; then
+    continue
+  fi
+  # Get architectures for current file
+  archs="$(lipo -info "${file}" | rev | cut -d ':' -f1 | rev)"
+  stripped=""
+  for arch in $archs; do
+    if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
+      # Strip non-valid architectures in-place
+      lipo -remove "$arch" -output "$file" "$file" || exit 1
+      stripped="$stripped $arch"
+    fi
+  done
+  if [[ "$stripped" != "" ]]; then
+    echo "Stripped $file of architectures:$stripped"
+    if [ "${CODE_SIGNING_REQUIRED}" == "YES" ]; then
+      code_sign "${file}"
+    fi
+  fi
+done

+ 17 - 0
MobileLibrary/iOS/SampleApps/TunneledWebRequest/TunneledWebRequest.xcodeproj/project.pbxproj

@@ -157,6 +157,7 @@
 				662658E71DCB8CF300872F6C /* Frameworks */,
 				662658E81DCB8CF300872F6C /* Resources */,
 				662659221DCBC8CB00872F6C /* CopyFiles */,
+				6685BDD71E300A7800F0E414 /* ShellScript */,
 			);
 			buildRules = (
 			);
@@ -280,6 +281,22 @@
 		};
 /* End PBXResourcesBuildPhase section */
 
+/* Begin PBXShellScriptBuildPhase section */
+		6685BDD71E300A7800F0E414 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "bash \"${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/PsiphonTunnel.framework/strip-frameworks.sh\"";
+		};
+/* End PBXShellScriptBuildPhase section */
+
 /* Begin PBXSourcesBuildPhase section */
 		662658E61DCB8CF300872F6C /* Sources */ = {
 			isa = PBXSourcesBuildPhase;

+ 9 - 1
MobileLibrary/iOS/USAGE.md

@@ -32,7 +32,15 @@ This code is a canonical guide for integrating the Library.
 
 5. In the "Build Settings" for the target, click the `+` at the top, then "Add User-Defined Setting". Name the new setting `STRIP_BITCODE_FROM_COPIED_FILES` and set it to `NO`.
 
-6. In target Build Phases, add a "Copy Files" phase. Set "Destination" to "Frameworks". Add `PsiphonTunnel.framework` to the list. Ensure "Code Sign on Copy" is checked.
+6. In the "Build Phases" for the target, add a "Copy Files" phase. Set "Destination" to "Frameworks". Add `PsiphonTunnel.framework` to the list. Ensure "Code Sign on Copy" is checked.
+
+7. In the "Build Phases" for the target, add a "Run Script" phase. Set the script contents to:
+
+   ```no-highlight
+   bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/PsiphonTunnel.framework/strip-frameworks.sh"
+   ```
+
+   This step is required to work around an [App Store submission validation bug](http://www.openradar.me/23681704) that rejects apps containing a framework with simulator slices.
 
 ## Compiling and testing
 

+ 12 - 1
MobileLibrary/iOS/build-psiphon-framework.sh

@@ -1,5 +1,15 @@
 #!/usr/bin/env bash
 
+# This script takes one optional argument: 'private', if private plugins should
+# be used. It should be omitted if private plugins are not desired.
+if [[ $1 == "private" ]]; then
+  FORCE_PRIVATE_PLUGINS=true
+  echo "TRUE"
+else
+  FORCE_PRIVATE_PLUGINS=false
+  echo "FALSE"
+fi
+
 # -x echos commands. -u exits if an unintialized variable is used.
 # -e exits if a command returns an error.
 set -x -u -e
@@ -31,6 +41,7 @@ FRAMEWORK_BINARY="${INTERMEDIATE_OUPUT_DIR}/${INTERMEDIATE_OUPUT_FILE}/Versions/
 # The "OPENSSL" tag enables support of OpenSSL for use by IndistinguishableTLS.
 
 PRIVATE_PLUGINS_TAG=""
+if [[ ${FORCE_PRIVATE_PLUGINS} == true ]]; then PRIVATE_PLUGINS_TAG="PRIVATE_PLUGINS"; fi
 BUILD_TAGS="OPENSSL IOS ${PRIVATE_PLUGINS_TAG}"
 
 LIBSSL=${BASE_DIR}/OpenSSL-for-iPhone/lib/libssl.a
@@ -55,7 +66,7 @@ export PATH=${GOPATH}/bin:${PATH}
 rm -rf ${GOPATH}
 
 # When updating the pinned rev, you will have to manually delete go-ios-build
-GOMOBILE_PINNED_REV=c4d780faeb85123ee32b88e84fd022739ed8c124
+GOMOBILE_PINNED_REV=a0f998b2d8c7ee81ddbead9202dd5e0184a998ad
 GOMOBILE_PATH=${GOPATH}/src/golang.org/x/mobile/cmd/gomobile
 
 TUNNEL_CORE_SRC_DIR=${GOPATH}/src/github.com/Psiphon-Labs/psiphon-tunnel-core