Просмотр исходного кода

Android library: add option to manually start routing through tunnel.

Eugene Fryntov 6 лет назад
Родитель
Сommit
0d89ce718a
1 измененных файлов с 47 добавлено и 29 удалено
  1. 47 29
      MobileLibrary/Android/PsiphonTunnel/PsiphonTunnel.java

+ 47 - 29
MobileLibrary/Android/PsiphonTunnel/PsiphonTunnel.java

@@ -110,22 +110,32 @@ public class PsiphonTunnel {
     private AtomicBoolean mIsWaitingForNetworkConnectivity;
     private AtomicReference<String> mClientPlatformPrefix;
     private AtomicReference<String> mClientPlatformSuffix;
+    private final boolean mShouldRouteThroughTunnelAutomatically;
 
     // Only one PsiphonVpn instance may exist at a time, as the underlying
     // psi.Psi and tun2socks implementations each contain global state.
     private static PsiphonTunnel mPsiphonTunnel;
 
     public static synchronized PsiphonTunnel newPsiphonTunnel(HostService hostService) {
+        return newPsiphonTunnelImpl(hostService, true);
+    }
+
+    // The two argument override in case the host app wants to take control over calling routeThroughTunnel()
+    public static synchronized PsiphonTunnel newPsiphonTunnel(HostService hostService, boolean shouldRouteThroughTunnelAutomatically) {
+        return newPsiphonTunnelImpl(hostService, shouldRouteThroughTunnelAutomatically);
+    }
+
+    private static PsiphonTunnel newPsiphonTunnelImpl(HostService hostService, boolean shouldRouteThroughTunnelAutomatically) {
         if (mPsiphonTunnel != null) {
             mPsiphonTunnel.stop();
         }
         // Load the native go code embedded in psi.aar
         System.loadLibrary("gojni");
-        mPsiphonTunnel = new PsiphonTunnel(hostService);
+        mPsiphonTunnel = new PsiphonTunnel(hostService, shouldRouteThroughTunnelAutomatically);
         return mPsiphonTunnel;
     }
 
-    private PsiphonTunnel(HostService hostService) {
+    private PsiphonTunnel(HostService hostService, boolean shouldRouteThroughTunnelAutomatically) {
         mHostService = hostService;
         mVpnMode = new AtomicBoolean(false);
         mTunFd = new AtomicReference<ParcelFileDescriptor>();
@@ -134,6 +144,7 @@ public class PsiphonTunnel {
         mIsWaitingForNetworkConnectivity = new AtomicBoolean(false);
         mClientPlatformPrefix = new AtomicReference<String>("");
         mClientPlatformSuffix = new AtomicReference<String>("");
+        mShouldRouteThroughTunnelAutomatically = shouldRouteThroughTunnelAutomatically;
     }
 
     public Object clone() throws CloneNotSupportedException {
@@ -147,6 +158,10 @@ public class PsiphonTunnel {
     // To start, call in sequence: startRouting(), then startTunneling(). After startRouting()
     // succeeds, the caller must call stop() to clean up. These functions should not be called
     // concurrently. Do not call stop() while startRouting() or startTunneling() is in progress.
+    // In case the host application requests manual control of routing through tunnel by calling
+    // PsiphonTunnel.newPsiphonTunnel(HostService hostservice, shouldRouteThroughTunnelAutomatically = false)
+    // it should also call routeThroughTunnel() at some point, usually after receiving onConnected() callback,
+    // otherwise it will be called automatically.
 
     // Returns true when the VPN routing is established; returns false if the VPN could not
     // be started due to lack of prepare or revoked permissions (called should re-prepare and
@@ -159,6 +174,35 @@ public class PsiphonTunnel {
         return startVpn();
     }
 
+    // Starts routing traffic via tunnel by starting tun2socks if it is not running already.
+    // This will be called automatically right after tunnel gets connected in case the host application
+    // did not request a manual control over this functionality, see PsiphonTunnel.newPsiphonTunnel
+    public void routeThroughTunnel() {
+        if (!mRoutingThroughTunnel.compareAndSet(false, true)) {
+            return;
+        }
+        ParcelFileDescriptor tunFd = mTunFd.getAndSet(null);
+        if (tunFd == null) {
+            return;
+        }
+
+        String socksServerAddress = "127.0.0.1:" + Integer.toString(mLocalSocksProxyPort.get());
+        String udpgwServerAddress = "127.0.0.1:" + Integer.toString(UDPGW_SERVER_PORT);
+        startTun2Socks(
+                tunFd,
+                VPN_INTERFACE_MTU,
+                mPrivateAddress.mRouter,
+                VPN_INTERFACE_NETMASK,
+                socksServerAddress,
+                udpgwServerAddress,
+                true);
+
+        mHostService.onDiagnosticMessage("routing through tunnel");
+
+        // TODO: should double-check tunnel routing; see:
+        // https://bitbucket.org/psiphon/psiphon-circumvention-system/src/1dc5e4257dca99790109f3bf374e8ab3a0ead4d7/Android/PsiphonAndroidLibrary/src/com/psiphon3/psiphonlibrary/TunnelCore.java?at=default#cl-779
+    }
+
     // Throws an exception in error conditions. In the case of an exception, the routing
     // started by startRouting() is not immediately torn down (this allows the caller to control
     // exactly when VPN routing is stopped); caller should call stop() to clean up.
@@ -345,32 +389,6 @@ public class PsiphonTunnel {
         mLocalSocksProxyPort.set(port);
     }
 
-    private void routeThroughTunnel() {
-        if (!mRoutingThroughTunnel.compareAndSet(false, true)) {
-            return;
-        }
-        ParcelFileDescriptor tunFd = mTunFd.getAndSet(null);
-        if (tunFd == null) {
-            return;
-        }
-
-        String socksServerAddress = "127.0.0.1:" + Integer.toString(mLocalSocksProxyPort.get());
-        String udpgwServerAddress = "127.0.0.1:" + Integer.toString(UDPGW_SERVER_PORT);
-        startTun2Socks(
-                tunFd,
-                VPN_INTERFACE_MTU,
-                mPrivateAddress.mRouter,
-                VPN_INTERFACE_NETMASK,
-                socksServerAddress,
-                udpgwServerAddress,
-                true);
-
-        mHostService.onDiagnosticMessage("routing through tunnel");
-
-        // TODO: should double-check tunnel routing; see:
-        // https://bitbucket.org/psiphon/psiphon-circumvention-system/src/1dc5e4257dca99790109f3bf374e8ab3a0ead4d7/Android/PsiphonAndroidLibrary/src/com/psiphon3/psiphonlibrary/TunnelCore.java?at=default#cl-779
-    }
-
     private void stopVpn() {
         stopTun2Socks();
         ParcelFileDescriptor tunFd = mTunFd.getAndSet(null);
@@ -671,7 +689,7 @@ public class PsiphonTunnel {
             if (noticeType.equals("Tunnels")) {
                 int count = notice.getJSONObject("data").getInt("count");
                 if (count > 0) {
-                    if (isVpnMode()) {
+                    if (isVpnMode() && mShouldRouteThroughTunnelAutomatically) {
                         routeThroughTunnel();
                     }
                     mHostService.onConnected();