Browse Source

Testing and bug fixes in progress

Rod Hynes 11 years ago
parent
commit
139deff442

+ 5 - 5
AndroidApp/app/src/main/java/ca/psiphon/psibot/Service.java

@@ -64,12 +64,12 @@ public class Service extends VpnService {
             public void run() {
                 CountDownLatch tunnelStartedSignal = new CountDownLatch(1);
                 SocketProtector socketProtector = new SocketProtector(Service.this);
-                Client client = new Client(Service.this, tunnelStartedSignal);
+                Psiphon psiphon = new Psiphon(Service.this, tunnelStartedSignal);
                 try {
                     socketProtector.start();
                     // TODO: what if client local proxies unbind? in this case it's better if Go client keeps its proxies up permanently.
                     // TODO: monitor tunnel messages and update notification UI when re-connecting, etc.
-                    client.start();
+                    psiphon.start();
                     while (true) {
                         if (tunnelStartedSignal.await(100, TimeUnit.MILLISECONDS)) {
                             break;
@@ -78,7 +78,7 @@ public class Service extends VpnService {
                             throw new Utils.PsibotError("stopped while waiting tunnel");
                         }
                     }
-                    int localSocksProxyPort = client.getLocalSocksProxyPort();
+                    int localSocksProxyPort = psiphon.getLocalSocksProxyPort();
                     runVpn(localSocksProxyPort);
                     mStopSignal.await();
                 } catch (Utils.PsibotError e) {
@@ -87,7 +87,7 @@ public class Service extends VpnService {
                     Thread.currentThread().interrupt();
                 }
                 stopVpn();
-                client.stop();
+                psiphon.stop();
                 socketProtector.stop();
                 stopSelf();
             }
@@ -172,7 +172,7 @@ public class Service extends VpnService {
 
             if (vpnInterfaceFileDescriptor == null) {
                 // as per http://developer.android.com/reference/android/net/VpnService.Builder.html#establish%28%29
-                throw new Utils.PsibotError("application is not prepared or is revoked");
+                throw new Utils.PsibotError(errorMessage + ": application is not prepared or is revoked");
             }
         } catch(IllegalArgumentException e) {
             throw new Utils.PsibotError(errorMessage, e);

+ 1 - 8
AndroidApp/app/src/main/java/ca/psiphon/psibot/Utils.java

@@ -50,21 +50,14 @@ public class Utils {
     public static class PsibotError extends Exception {
         private static final long serialVersionUID = 1L;
 
-        public PsibotError() {
-            super();
-        }
-
         public PsibotError(String message) {
             super(message);
         }
 
         public PsibotError(String message, Throwable cause) {
-            super(message, cause);
+            super(message + ": " + cause.getMessage());
         }
 
-        public PsibotError(Throwable cause) {
-            super(cause);
-        }
     }
 
     public static void writeRawResourceFile(

+ 26 - 26
AndroidApp/app/src/main/java/go/Go.java

@@ -7,41 +7,41 @@ import android.util.Log;
 // Go is an entry point for libraries compiled in Go.
 // In an app's Application.onCreate, call:
 //
-//  Go.init(getApplicationContext());
+// 	Go.init(getApplicationContext());
 //
 // When the function returns, it is safe to start calling
 // Go code.
 public final class Go {
-    // init loads libgojni.so and starts the runtime.
-    public static void init(Context context) {
-        if (Looper.myLooper() != Looper.getMainLooper()) {
-            Log.wtf("Go", "Go.init must be called from main thread (looper="+Looper.myLooper().toString()+")");
-        }
-        if (running) {
-            return;
-        }
-        running = true;
-
-        // TODO(crawshaw): setenv TMPDIR to context.getCacheDir().getAbsolutePath()
-        // TODO(crawshaw): context.registerComponentCallbacks for runtime.GC
-
-        System.loadLibrary("gojni");
-
-        new Thread("GoMain") {
-            public void run() {
-                Go.run();
-            }
-        }.start();
+	// init loads libgojni.so and starts the runtime.
+	public static void init(Context context) {
+		if (Looper.myLooper() != Looper.getMainLooper()) {
+			Log.wtf("Go", "Go.init must be called from main thread (looper="+Looper.myLooper().toString()+")");
+		}
+		if (running) {
+			return;
+		}
+		running = true;
+
+		// TODO(crawshaw): setenv TMPDIR to context.getCacheDir().getAbsolutePath()
+		// TODO(crawshaw): context.registerComponentCallbacks for runtime.GC
+
+		System.loadLibrary("gojni");
+
+		new Thread("GoMain") {
+			public void run() {
+				Go.run();
+			}
+		}.start();
 
-        Go.waitForRun();
+		Go.waitForRun();
 
         new Thread("GoReceive") {
             public void run() { Seq.receive(); }
         }.start();
-    }
+	}
 
-    private static boolean running = false;
+	private static boolean running = false;
 
-    private static native void run();
-    private static native void waitForRun();
+	private static native void run();
+	private static native void waitForRun();
 }

+ 238 - 238
AndroidApp/app/src/main/java/go/Seq.java

@@ -10,242 +10,242 @@ import java.util.concurrent.Executors;
 // Seq is a sequence of machine-dependent encoded values.
 // Used by automatically generated language bindings to talk to Go.
 public class Seq {
-    @SuppressWarnings("UnusedDeclaration")
-    private long memptr; // holds C-allocated pointer
-
-    public Seq() {
-        ensure(64);
-    }
-
-    // Ensure that at least size bytes can be written to the Seq.
-    // Any existing data in the buffer is preserved.
-    public native void ensure(int size);
-
-    // Moves the internal buffer offset back to zero.
-    // Length and contents are maintained. Data can be read after a reset.
-    public native void resetOffset();
-
-    public native void log(String label);
-
-    public native byte readInt8();
-    public native short readInt16();
-    public native int readInt32();
-    public native long readInt64();
-    public long readInt() { return readInt64(); }
-
-    public native float readFloat32();
-    public native double readFloat64();
-    public native String readUTF16();
-    public native byte[] readByteArray();
-
-    public native void writeInt8(byte v);
-    public native void writeInt16(short v);
-    public native void writeInt32(int v);
-    public native void writeInt64(long v);
-    public void writeInt(long v) { writeInt64(v); }
-
-    public native void writeFloat32(float v);
-    public native void writeFloat64(double v);
-    public native void writeUTF16(String v);
-    public native void writeByteArray(byte[] v);
-
-    public void writeRef(Ref ref) {
-        writeInt32(ref.refnum);
-    }
-
-    public Ref readRef() {
-        int refnum = readInt32();
-        return tracker.get(refnum);
-    }
-
-    // Informs the Go ref tracker that Java is done with this ref.
-    static native void destroyRef(int refnum);
-
-    // createRef creates a Ref to a Java object.
-    public static Ref createRef(Seq.Object o) {
-        return tracker.createRef(o);
-    }
-
-    // sends a function invocation request to Go.
-    //
-    // Blocks until the function completes.
-    // If the request is for a method, the first element in src is
-    // a Ref to the receiver.
-    public static native void send(String descriptor, int code, Seq src, Seq dst);
-
-    // recv returns the next request from Go for a Java call.
-    static native void recv(Seq in, Receive params);
-
-    // recvRes sends the result of a Java call back to Go.
-    static native void recvRes(int handle, Seq out);
-
-    static final class Receive {
-        int refnum;
-        int code;
-        int handle;
-    }
-
-    protected void finalize() throws Throwable {
-        super.finalize();
-        free();
-    }
-    private native void free();
-
-    private static final ExecutorService receivePool = Executors.newCachedThreadPool();
-
-    // receive listens for callback requests from Go, invokes them on a thread
-    // pool and sends the responses.
-    public static void receive() {
-        Seq.Receive params = new Seq.Receive();
-        while (true) {
-            final Seq in = new Seq();
-            Seq.recv(in, params);
-
-            final int code = params.code;
-            final int handle = params.handle;
-            final int refnum = params.refnum;
-
-            if (code == -1) {
-                // Special signal from seq.FinalizeRef.
-                tracker.dec(refnum);
-                Seq out = new Seq();
-                Seq.recvRes(handle, out);
-                continue;
-            }
-
-            receivePool.execute(new Runnable() {
-                public void run() {
-                    Ref r = tracker.get(refnum);
-                    Seq out = new Seq();
-                    r.obj.call(code, in, out);
-                    Seq.recvRes(handle, out);
-                }
-            });
-        }
-    }
-
-    // An Object is a Java object that matches a Go object.
-    // The implementation of the object may be in either Java or Go,
-    // with a proxy instance in the other language passing calls
-    // through to the other language.
-    //
-    // Don't implement an Object directly. Instead, look for the
-    // generated abstract Stub.
-    public interface Object {
-        public Ref ref();
-        public void call(int code, Seq in, Seq out);
-    }
-
-    // A Ref is an object tagged with an integer for passing back and
-    // forth across the language boundary.
-    //
-    // A Ref may represent either an instance of a Java Object subclass,
-    // or an instance of a Go object. The explicit allocation of a Ref
-    // is used to pin Go object instances when they are passed to Java.
-    // The Go Seq library maintains a reference to the instance in a map
-    // keyed by the Ref number. When the JVM calls finalize, we ask Go
-    // to clear the entry in the map.
-    public static final class Ref {
-        // ref < 0: Go object tracked by Java
-        // ref > 0: Java object tracked by Go
-        int refnum;
-        public Seq.Object obj;
-
-        private Ref(int refnum, Seq.Object o) {
-            this.refnum = refnum;
-            this.obj = o;
-            tracker.inc(refnum);
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            tracker.dec(refnum);
-            super.finalize();
-        }
-    }
-
-    static final RefTracker tracker = new RefTracker();
-
-    static final class RefTracker {
-        // Next Java object reference number.
-        //
-        // Reference numbers are positive for Java objects,
-        // and start, arbitrarily at a different offset to Go
-        // to make debugging by reading Seq hex a little easier.
-        private int next = 42; // next Java object ref
-
-        // TODO(crawshaw): We could cut down allocations for frequently
-        // sent Go objects by maintaining a map to weak references. This
-        // however, would require allocating two objects per reference
-        // instead of one. It also introduces weak references, the bane
-        // of any Java debugging session.
-        //
-        // When we have real code, examine the tradeoffs.
-
-        // Number of active references to a Go object. refnum -> count
-        private SparseIntArray goObjs = new SparseIntArray();
-
-        // Java objects that have been passed to Go. refnum -> Ref
-        // The Ref obj field is non-null.
-        // This map pins Java objects so they don't get GCed while the
-        // only reference to them is held by Go code.
-        private SparseArray<Ref> javaObjs = new SparseArray<Ref>();
-
-        // inc increments the reference count to a Go object.
-        synchronized void inc(int refnum) {
-            if (refnum > 0) {
-                return; // we don't count java objects
-            }
-            int count = goObjs.get(refnum);
-            if (count == Integer.MAX_VALUE) {
-                throw new RuntimeException("refnum " + refnum + " overflow");
-            }
-            goObjs.put(refnum, count+1);
-        }
-
-        // dec decrements the reference count to a Go object.
-        // If the count reaches zero, the Go reference tracker is informed.
-        synchronized void dec(int refnum) {
-            if (refnum > 0) {
-                // Java objects are removed on request of Go.
-                javaObjs.remove(refnum);
-                return;
-            }
-            int count = goObjs.get(refnum);
-            if (count == 0) {
-                throw new RuntimeException("refnum " + refnum + " underflow");
-            }
-            count--;
-            if (count <= 0) {
-                goObjs.delete(refnum);
-                Seq.destroyRef(refnum);
-            } else {
-                goObjs.put(refnum, count);
-            }
-        }
-
-        synchronized Ref createRef(Seq.Object o) {
-            // TODO(crawshaw): use single Ref for null.
-            if (next == Integer.MAX_VALUE) {
-                throw new RuntimeException("createRef overflow for " + o);
-            }
-            int refnum = next++;
-            Ref ref = new Ref(refnum, o);
-            javaObjs.put(refnum, ref);
-            return ref;
-        }
-
-        // get returns an existing Ref to either a Java or Go object.
-        // It may be the first time we have seen the Go object.
-        synchronized Ref get(int refnum) {
-            if (refnum > 0) {
-                Ref ref = javaObjs.get(refnum);
-                if (ref == null) {
-                    throw new RuntimeException("unknown java Ref: "+refnum);
-                }
-                return ref;
-            }
-            return new Ref(refnum, null);
-        }
-    }
+	@SuppressWarnings("UnusedDeclaration")
+	private long memptr; // holds C-allocated pointer
+
+	public Seq() {
+		ensure(64);
+	}
+
+	// Ensure that at least size bytes can be written to the Seq.
+	// Any existing data in the buffer is preserved.
+	public native void ensure(int size);
+
+	// Moves the internal buffer offset back to zero.
+	// Length and contents are maintained. Data can be read after a reset.
+	public native void resetOffset();
+
+	public native void log(String label);
+
+	public native byte readInt8();
+	public native short readInt16();
+	public native int readInt32();
+	public native long readInt64();
+	public long readInt() { return readInt64(); }
+
+	public native float readFloat32();
+	public native double readFloat64();
+	public native String readUTF16();
+	public native byte[] readByteArray();
+
+	public native void writeInt8(byte v);
+	public native void writeInt16(short v);
+	public native void writeInt32(int v);
+	public native void writeInt64(long v);
+	public void writeInt(long v) { writeInt64(v); }
+
+	public native void writeFloat32(float v);
+	public native void writeFloat64(double v);
+	public native void writeUTF16(String v);
+	public native void writeByteArray(byte[] v);
+
+	public void writeRef(Ref ref) {
+		writeInt32(ref.refnum);
+	}
+
+	public Ref readRef() {
+		int refnum = readInt32();
+		return tracker.get(refnum);
+	}
+
+	// Informs the Go ref tracker that Java is done with this ref.
+	static native void destroyRef(int refnum);
+
+	// createRef creates a Ref to a Java object.
+	public static Ref createRef(Seq.Object o) {
+		return tracker.createRef(o);
+	}
+
+	// sends a function invocation request to Go.
+	//
+	// Blocks until the function completes.
+	// If the request is for a method, the first element in src is
+	// a Ref to the receiver.
+	public static native void send(String descriptor, int code, Seq src, Seq dst);
+
+	// recv returns the next request from Go for a Java call.
+	static native void recv(Seq in, Receive params);
+
+	// recvRes sends the result of a Java call back to Go.
+	static native void recvRes(int handle, Seq out);
+
+	static final class Receive {
+		int refnum;
+		int code;
+		int handle;
+	}
+
+	protected void finalize() throws Throwable {
+		super.finalize();
+		free();
+	}
+	private native void free();
+
+	private static final ExecutorService receivePool = Executors.newCachedThreadPool();
+
+	// receive listens for callback requests from Go, invokes them on a thread
+	// pool and sends the responses.
+	public static void receive() {
+		Seq.Receive params = new Seq.Receive();
+		while (true) {
+			final Seq in = new Seq();
+			Seq.recv(in, params);
+
+			final int code = params.code;
+			final int handle = params.handle;
+			final int refnum = params.refnum;
+
+			if (code == -1) {
+				// Special signal from seq.FinalizeRef.
+				tracker.dec(refnum);
+				Seq out = new Seq();
+				Seq.recvRes(handle, out);
+				continue;
+			}
+
+			receivePool.execute(new Runnable() {
+				public void run() {
+					Ref r = tracker.get(refnum);
+					Seq out = new Seq();
+					r.obj.call(code, in, out);
+					Seq.recvRes(handle, out);
+				}
+			});
+		}
+	}
+
+	// An Object is a Java object that matches a Go object.
+	// The implementation of the object may be in either Java or Go,
+	// with a proxy instance in the other language passing calls
+	// through to the other language.
+	//
+	// Don't implement an Object directly. Instead, look for the
+	// generated abstract Stub.
+	public interface Object {
+		public Ref ref();
+		public void call(int code, Seq in, Seq out);
+	}
+
+	// A Ref is an object tagged with an integer for passing back and
+	// forth across the language boundary.
+	//
+	// A Ref may represent either an instance of a Java Object subclass,
+	// or an instance of a Go object. The explicit allocation of a Ref
+	// is used to pin Go object instances when they are passed to Java.
+	// The Go Seq library maintains a reference to the instance in a map
+	// keyed by the Ref number. When the JVM calls finalize, we ask Go
+	// to clear the entry in the map.
+	public static final class Ref {
+		// ref < 0: Go object tracked by Java
+		// ref > 0: Java object tracked by Go
+		int refnum;
+		public Seq.Object obj;
+
+		private Ref(int refnum, Seq.Object o) {
+			this.refnum = refnum;
+			this.obj = o;
+			tracker.inc(refnum);
+		}
+
+		@Override
+		protected void finalize() throws Throwable {
+			tracker.dec(refnum);
+			super.finalize();
+		}
+	}
+
+	static final RefTracker tracker = new RefTracker();
+
+	static final class RefTracker {
+		// Next Java object reference number.
+		//
+		// Reference numbers are positive for Java objects,
+		// and start, arbitrarily at a different offset to Go
+		// to make debugging by reading Seq hex a little easier.
+		private int next = 42; // next Java object ref
+
+		// TODO(crawshaw): We could cut down allocations for frequently
+		// sent Go objects by maintaining a map to weak references. This
+		// however, would require allocating two objects per reference
+		// instead of one. It also introduces weak references, the bane
+		// of any Java debugging session.
+		//
+		// When we have real code, examine the tradeoffs.
+
+		// Number of active references to a Go object. refnum -> count
+		private SparseIntArray goObjs = new SparseIntArray();
+
+		// Java objects that have been passed to Go. refnum -> Ref
+		// The Ref obj field is non-null.
+		// This map pins Java objects so they don't get GCed while the
+		// only reference to them is held by Go code.
+		private SparseArray<Ref> javaObjs = new SparseArray<Ref>();
+
+		// inc increments the reference count to a Go object.
+		synchronized void inc(int refnum) {
+			if (refnum > 0) {
+				return; // we don't count java objects
+			}
+			int count = goObjs.get(refnum);
+			if (count == Integer.MAX_VALUE) {
+				throw new RuntimeException("refnum " + refnum + " overflow");
+			}
+			goObjs.put(refnum, count+1);
+		}
+
+		// dec decrements the reference count to a Go object.
+		// If the count reaches zero, the Go reference tracker is informed.
+		synchronized void dec(int refnum) {
+			if (refnum > 0) {
+				// Java objects are removed on request of Go.
+				javaObjs.remove(refnum);
+				return;
+			}
+			int count = goObjs.get(refnum);
+			if (count == 0) {
+				throw new RuntimeException("refnum " + refnum + " underflow");
+			}
+			count--;
+			if (count <= 0) {
+				goObjs.delete(refnum);
+				Seq.destroyRef(refnum);
+			} else {
+				goObjs.put(refnum, count);
+			}
+		}
+
+		synchronized Ref createRef(Seq.Object o) {
+			// TODO(crawshaw): use single Ref for null.
+			if (next == Integer.MAX_VALUE) {
+				throw new RuntimeException("createRef overflow for " + o);
+			}
+			int refnum = next++;
+			Ref ref = new Ref(refnum, o);
+			javaObjs.put(refnum, ref);
+			return ref;
+		}
+
+		// get returns an existing Ref to either a Java or Go object.
+		// It may be the first time we have seen the Go object.
+		synchronized Ref get(int refnum) {
+			if (refnum > 0) {
+				Ref ref = javaObjs.get(refnum);
+				if (ref == null) {
+					throw new RuntimeException("unknown java Ref: "+refnum);
+				}
+				return ref;
+			}
+			return new Ref(refnum, null);
+		}
+	}
 }

BIN
AndroidApp/app/src/main/jniLibs/armeabi-v7a/libgojni.so


+ 9 - 5
AndroidLibrary/README.md

@@ -5,7 +5,8 @@ Overview
 --------------------------------------------------------------------------------
 
 Psiphon Library for Android enables you to easily embed Psiphon in your Android
-app.
+app. The Psiphon Library for Android is implemented in Go and follows the standard
+conventions for using a Go library in an Android app.
 
 Status
 --------------------------------------------------------------------------------
@@ -15,15 +16,15 @@ Status
 Building From Source
 --------------------------------------------------------------------------------
 
-Review Go Android documentation:
-* [Main README](https://code.google.com/p/go/source/browse/README?repo=mobile)
+Follow Go Android documentation:
+* [Overview README](https://code.google.com/p/go/source/browse/README?repo=mobile)
 * [Sample JNI App README](https://code.google.com/p/go/source/browse/example/libhello/README?repo=mobile)
 * [gobind documentation](http://godoc.org/golang.org/x/mobile/cmd/gobind)
 
 ```
 /AndroidLibrary
   README.md                - this file
-  gojni.so                 - build binary output
+  libgojni.so              - build binary output
   /psi
     psi.go                 - main library source
   /go_psi
@@ -37,11 +38,13 @@ Review Go Android documentation:
     main.go                - stub main package for library
 ```
 
+NOTE: may change after Go 1.4 is released.
+
 * Requires Go 1.4 or later
   * At this time, android/arm support is not yet released but.
   * Install Go from source. The Android instructions are here:
 [https://code.google.com/p/go/source/browse/README?repo=mobile](https://code.google.com/p/go/source/browse/README?repo=mobile).
-  * In summary, download and install the Android NDK, use a script to make a standalone toolchain, and use that toolchain to build android/arm support within the Go source install. Then cross compile as usual.
+  * In summary, download and install the Android NDK, use a script to make a [standalone toolchain](https://developer.android.com/tools/sdk/ndk/index.html#Docs), and use that toolchain to build android/arm support within the Go source install. Then cross compile as usual.
 * `$GOPATH/bin/gobind -lang=go github.com/Psiphon-Labs/psiphon-tunnel-core/AndroidLibrary/psi > go_psi/go_psi.go`
 * `$GOPATH/bin/gobind -lang=java github.com/Psiphon-Labs/psiphon-tunnel-core/AndroidLibrary/psi > java_psi/go/psi/Psi.java`
 * In `/libpsi` `CGO_ENABLED=1 GOOS=android GOARCH=arm GOARM=7 go build -ldflags="-shared"` and copy output file to `gojni.so`
@@ -49,6 +52,7 @@ Review Go Android documentation:
 Using
 --------------------------------------------------------------------------------
 
+1. Build from source or use the provided shared object binary and Java source files
 1. Add Go/Java integration files `java_golang/go/*.java` to your `$src/go`
 1. Add `java_psi/go/psi/Psi.java` to your `$src/go/psi`
 1. Add `gojni.so

+ 26 - 26
AndroidLibrary/java_golang/go/Go.java

@@ -7,41 +7,41 @@ import android.util.Log;
 // Go is an entry point for libraries compiled in Go.
 // In an app's Application.onCreate, call:
 //
-//  Go.init(getApplicationContext());
+// 	Go.init(getApplicationContext());
 //
 // When the function returns, it is safe to start calling
 // Go code.
 public final class Go {
-    // init loads libgojni.so and starts the runtime.
-    public static void init(Context context) {
-        if (Looper.myLooper() != Looper.getMainLooper()) {
-            Log.wtf("Go", "Go.init must be called from main thread (looper="+Looper.myLooper().toString()+")");
-        }
-        if (running) {
-            return;
-        }
-        running = true;
-
-        // TODO(crawshaw): setenv TMPDIR to context.getCacheDir().getAbsolutePath()
-        // TODO(crawshaw): context.registerComponentCallbacks for runtime.GC
-
-        System.loadLibrary("gojni");
-
-        new Thread("GoMain") {
-            public void run() {
-                Go.run();
-            }
-        }.start();
+	// init loads libgojni.so and starts the runtime.
+	public static void init(Context context) {
+		if (Looper.myLooper() != Looper.getMainLooper()) {
+			Log.wtf("Go", "Go.init must be called from main thread (looper="+Looper.myLooper().toString()+")");
+		}
+		if (running) {
+			return;
+		}
+		running = true;
+
+		// TODO(crawshaw): setenv TMPDIR to context.getCacheDir().getAbsolutePath()
+		// TODO(crawshaw): context.registerComponentCallbacks for runtime.GC
+
+		System.loadLibrary("gojni");
+
+		new Thread("GoMain") {
+			public void run() {
+				Go.run();
+			}
+		}.start();
 
-        Go.waitForRun();
+		Go.waitForRun();
 
         new Thread("GoReceive") {
             public void run() { Seq.receive(); }
         }.start();
-    }
+	}
 
-    private static boolean running = false;
+	private static boolean running = false;
 
-    private static native void run();
-    private static native void waitForRun();
+	private static native void run();
+	private static native void waitForRun();
 }

+ 238 - 238
AndroidLibrary/java_golang/go/Seq.java

@@ -10,242 +10,242 @@ import java.util.concurrent.Executors;
 // Seq is a sequence of machine-dependent encoded values.
 // Used by automatically generated language bindings to talk to Go.
 public class Seq {
-    @SuppressWarnings("UnusedDeclaration")
-    private long memptr; // holds C-allocated pointer
-
-    public Seq() {
-        ensure(64);
-    }
-
-    // Ensure that at least size bytes can be written to the Seq.
-    // Any existing data in the buffer is preserved.
-    public native void ensure(int size);
-
-    // Moves the internal buffer offset back to zero.
-    // Length and contents are maintained. Data can be read after a reset.
-    public native void resetOffset();
-
-    public native void log(String label);
-
-    public native byte readInt8();
-    public native short readInt16();
-    public native int readInt32();
-    public native long readInt64();
-    public long readInt() { return readInt64(); }
-
-    public native float readFloat32();
-    public native double readFloat64();
-    public native String readUTF16();
-    public native byte[] readByteArray();
-
-    public native void writeInt8(byte v);
-    public native void writeInt16(short v);
-    public native void writeInt32(int v);
-    public native void writeInt64(long v);
-    public void writeInt(long v) { writeInt64(v); }
-
-    public native void writeFloat32(float v);
-    public native void writeFloat64(double v);
-    public native void writeUTF16(String v);
-    public native void writeByteArray(byte[] v);
-
-    public void writeRef(Ref ref) {
-        writeInt32(ref.refnum);
-    }
-
-    public Ref readRef() {
-        int refnum = readInt32();
-        return tracker.get(refnum);
-    }
-
-    // Informs the Go ref tracker that Java is done with this ref.
-    static native void destroyRef(int refnum);
-
-    // createRef creates a Ref to a Java object.
-    public static Ref createRef(Seq.Object o) {
-        return tracker.createRef(o);
-    }
-
-    // sends a function invocation request to Go.
-    //
-    // Blocks until the function completes.
-    // If the request is for a method, the first element in src is
-    // a Ref to the receiver.
-    public static native void send(String descriptor, int code, Seq src, Seq dst);
-
-    // recv returns the next request from Go for a Java call.
-    static native void recv(Seq in, Receive params);
-
-    // recvRes sends the result of a Java call back to Go.
-    static native void recvRes(int handle, Seq out);
-
-    static final class Receive {
-        int refnum;
-        int code;
-        int handle;
-    }
-
-    protected void finalize() throws Throwable {
-        super.finalize();
-        free();
-    }
-    private native void free();
-
-    private static final ExecutorService receivePool = Executors.newCachedThreadPool();
-
-    // receive listens for callback requests from Go, invokes them on a thread
-    // pool and sends the responses.
-    public static void receive() {
-        Seq.Receive params = new Seq.Receive();
-        while (true) {
-            final Seq in = new Seq();
-            Seq.recv(in, params);
-
-            final int code = params.code;
-            final int handle = params.handle;
-            final int refnum = params.refnum;
-
-            if (code == -1) {
-                // Special signal from seq.FinalizeRef.
-                tracker.dec(refnum);
-                Seq out = new Seq();
-                Seq.recvRes(handle, out);
-                continue;
-            }
-
-            receivePool.execute(new Runnable() {
-                public void run() {
-                    Ref r = tracker.get(refnum);
-                    Seq out = new Seq();
-                    r.obj.call(code, in, out);
-                    Seq.recvRes(handle, out);
-                }
-            });
-        }
-    }
-
-    // An Object is a Java object that matches a Go object.
-    // The implementation of the object may be in either Java or Go,
-    // with a proxy instance in the other language passing calls
-    // through to the other language.
-    //
-    // Don't implement an Object directly. Instead, look for the
-    // generated abstract Stub.
-    public interface Object {
-        public Ref ref();
-        public void call(int code, Seq in, Seq out);
-    }
-
-    // A Ref is an object tagged with an integer for passing back and
-    // forth across the language boundary.
-    //
-    // A Ref may represent either an instance of a Java Object subclass,
-    // or an instance of a Go object. The explicit allocation of a Ref
-    // is used to pin Go object instances when they are passed to Java.
-    // The Go Seq library maintains a reference to the instance in a map
-    // keyed by the Ref number. When the JVM calls finalize, we ask Go
-    // to clear the entry in the map.
-    public static final class Ref {
-        // ref < 0: Go object tracked by Java
-        // ref > 0: Java object tracked by Go
-        int refnum;
-        public Seq.Object obj;
-
-        private Ref(int refnum, Seq.Object o) {
-            this.refnum = refnum;
-            this.obj = o;
-            tracker.inc(refnum);
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            tracker.dec(refnum);
-            super.finalize();
-        }
-    }
-
-    static final RefTracker tracker = new RefTracker();
-
-    static final class RefTracker {
-        // Next Java object reference number.
-        //
-        // Reference numbers are positive for Java objects,
-        // and start, arbitrarily at a different offset to Go
-        // to make debugging by reading Seq hex a little easier.
-        private int next = 42; // next Java object ref
-
-        // TODO(crawshaw): We could cut down allocations for frequently
-        // sent Go objects by maintaining a map to weak references. This
-        // however, would require allocating two objects per reference
-        // instead of one. It also introduces weak references, the bane
-        // of any Java debugging session.
-        //
-        // When we have real code, examine the tradeoffs.
-
-        // Number of active references to a Go object. refnum -> count
-        private SparseIntArray goObjs = new SparseIntArray();
-
-        // Java objects that have been passed to Go. refnum -> Ref
-        // The Ref obj field is non-null.
-        // This map pins Java objects so they don't get GCed while the
-        // only reference to them is held by Go code.
-        private SparseArray<Ref> javaObjs = new SparseArray<Ref>();
-
-        // inc increments the reference count to a Go object.
-        synchronized void inc(int refnum) {
-            if (refnum > 0) {
-                return; // we don't count java objects
-            }
-            int count = goObjs.get(refnum);
-            if (count == Integer.MAX_VALUE) {
-                throw new RuntimeException("refnum " + refnum + " overflow");
-            }
-            goObjs.put(refnum, count+1);
-        }
-
-        // dec decrements the reference count to a Go object.
-        // If the count reaches zero, the Go reference tracker is informed.
-        synchronized void dec(int refnum) {
-            if (refnum > 0) {
-                // Java objects are removed on request of Go.
-                javaObjs.remove(refnum);
-                return;
-            }
-            int count = goObjs.get(refnum);
-            if (count == 0) {
-                throw new RuntimeException("refnum " + refnum + " underflow");
-            }
-            count--;
-            if (count <= 0) {
-                goObjs.delete(refnum);
-                Seq.destroyRef(refnum);
-            } else {
-                goObjs.put(refnum, count);
-            }
-        }
-
-        synchronized Ref createRef(Seq.Object o) {
-            // TODO(crawshaw): use single Ref for null.
-            if (next == Integer.MAX_VALUE) {
-                throw new RuntimeException("createRef overflow for " + o);
-            }
-            int refnum = next++;
-            Ref ref = new Ref(refnum, o);
-            javaObjs.put(refnum, ref);
-            return ref;
-        }
-
-        // get returns an existing Ref to either a Java or Go object.
-        // It may be the first time we have seen the Go object.
-        synchronized Ref get(int refnum) {
-            if (refnum > 0) {
-                Ref ref = javaObjs.get(refnum);
-                if (ref == null) {
-                    throw new RuntimeException("unknown java Ref: "+refnum);
-                }
-                return ref;
-            }
-            return new Ref(refnum, null);
-        }
-    }
+	@SuppressWarnings("UnusedDeclaration")
+	private long memptr; // holds C-allocated pointer
+
+	public Seq() {
+		ensure(64);
+	}
+
+	// Ensure that at least size bytes can be written to the Seq.
+	// Any existing data in the buffer is preserved.
+	public native void ensure(int size);
+
+	// Moves the internal buffer offset back to zero.
+	// Length and contents are maintained. Data can be read after a reset.
+	public native void resetOffset();
+
+	public native void log(String label);
+
+	public native byte readInt8();
+	public native short readInt16();
+	public native int readInt32();
+	public native long readInt64();
+	public long readInt() { return readInt64(); }
+
+	public native float readFloat32();
+	public native double readFloat64();
+	public native String readUTF16();
+	public native byte[] readByteArray();
+
+	public native void writeInt8(byte v);
+	public native void writeInt16(short v);
+	public native void writeInt32(int v);
+	public native void writeInt64(long v);
+	public void writeInt(long v) { writeInt64(v); }
+
+	public native void writeFloat32(float v);
+	public native void writeFloat64(double v);
+	public native void writeUTF16(String v);
+	public native void writeByteArray(byte[] v);
+
+	public void writeRef(Ref ref) {
+		writeInt32(ref.refnum);
+	}
+
+	public Ref readRef() {
+		int refnum = readInt32();
+		return tracker.get(refnum);
+	}
+
+	// Informs the Go ref tracker that Java is done with this ref.
+	static native void destroyRef(int refnum);
+
+	// createRef creates a Ref to a Java object.
+	public static Ref createRef(Seq.Object o) {
+		return tracker.createRef(o);
+	}
+
+	// sends a function invocation request to Go.
+	//
+	// Blocks until the function completes.
+	// If the request is for a method, the first element in src is
+	// a Ref to the receiver.
+	public static native void send(String descriptor, int code, Seq src, Seq dst);
+
+	// recv returns the next request from Go for a Java call.
+	static native void recv(Seq in, Receive params);
+
+	// recvRes sends the result of a Java call back to Go.
+	static native void recvRes(int handle, Seq out);
+
+	static final class Receive {
+		int refnum;
+		int code;
+		int handle;
+	}
+
+	protected void finalize() throws Throwable {
+		super.finalize();
+		free();
+	}
+	private native void free();
+
+	private static final ExecutorService receivePool = Executors.newCachedThreadPool();
+
+	// receive listens for callback requests from Go, invokes them on a thread
+	// pool and sends the responses.
+	public static void receive() {
+		Seq.Receive params = new Seq.Receive();
+		while (true) {
+			final Seq in = new Seq();
+			Seq.recv(in, params);
+
+			final int code = params.code;
+			final int handle = params.handle;
+			final int refnum = params.refnum;
+
+			if (code == -1) {
+				// Special signal from seq.FinalizeRef.
+				tracker.dec(refnum);
+				Seq out = new Seq();
+				Seq.recvRes(handle, out);
+				continue;
+			}
+
+			receivePool.execute(new Runnable() {
+				public void run() {
+					Ref r = tracker.get(refnum);
+					Seq out = new Seq();
+					r.obj.call(code, in, out);
+					Seq.recvRes(handle, out);
+				}
+			});
+		}
+	}
+
+	// An Object is a Java object that matches a Go object.
+	// The implementation of the object may be in either Java or Go,
+	// with a proxy instance in the other language passing calls
+	// through to the other language.
+	//
+	// Don't implement an Object directly. Instead, look for the
+	// generated abstract Stub.
+	public interface Object {
+		public Ref ref();
+		public void call(int code, Seq in, Seq out);
+	}
+
+	// A Ref is an object tagged with an integer for passing back and
+	// forth across the language boundary.
+	//
+	// A Ref may represent either an instance of a Java Object subclass,
+	// or an instance of a Go object. The explicit allocation of a Ref
+	// is used to pin Go object instances when they are passed to Java.
+	// The Go Seq library maintains a reference to the instance in a map
+	// keyed by the Ref number. When the JVM calls finalize, we ask Go
+	// to clear the entry in the map.
+	public static final class Ref {
+		// ref < 0: Go object tracked by Java
+		// ref > 0: Java object tracked by Go
+		int refnum;
+		public Seq.Object obj;
+
+		private Ref(int refnum, Seq.Object o) {
+			this.refnum = refnum;
+			this.obj = o;
+			tracker.inc(refnum);
+		}
+
+		@Override
+		protected void finalize() throws Throwable {
+			tracker.dec(refnum);
+			super.finalize();
+		}
+	}
+
+	static final RefTracker tracker = new RefTracker();
+
+	static final class RefTracker {
+		// Next Java object reference number.
+		//
+		// Reference numbers are positive for Java objects,
+		// and start, arbitrarily at a different offset to Go
+		// to make debugging by reading Seq hex a little easier.
+		private int next = 42; // next Java object ref
+
+		// TODO(crawshaw): We could cut down allocations for frequently
+		// sent Go objects by maintaining a map to weak references. This
+		// however, would require allocating two objects per reference
+		// instead of one. It also introduces weak references, the bane
+		// of any Java debugging session.
+		//
+		// When we have real code, examine the tradeoffs.
+
+		// Number of active references to a Go object. refnum -> count
+		private SparseIntArray goObjs = new SparseIntArray();
+
+		// Java objects that have been passed to Go. refnum -> Ref
+		// The Ref obj field is non-null.
+		// This map pins Java objects so they don't get GCed while the
+		// only reference to them is held by Go code.
+		private SparseArray<Ref> javaObjs = new SparseArray<Ref>();
+
+		// inc increments the reference count to a Go object.
+		synchronized void inc(int refnum) {
+			if (refnum > 0) {
+				return; // we don't count java objects
+			}
+			int count = goObjs.get(refnum);
+			if (count == Integer.MAX_VALUE) {
+				throw new RuntimeException("refnum " + refnum + " overflow");
+			}
+			goObjs.put(refnum, count+1);
+		}
+
+		// dec decrements the reference count to a Go object.
+		// If the count reaches zero, the Go reference tracker is informed.
+		synchronized void dec(int refnum) {
+			if (refnum > 0) {
+				// Java objects are removed on request of Go.
+				javaObjs.remove(refnum);
+				return;
+			}
+			int count = goObjs.get(refnum);
+			if (count == 0) {
+				throw new RuntimeException("refnum " + refnum + " underflow");
+			}
+			count--;
+			if (count <= 0) {
+				goObjs.delete(refnum);
+				Seq.destroyRef(refnum);
+			} else {
+				goObjs.put(refnum, count);
+			}
+		}
+
+		synchronized Ref createRef(Seq.Object o) {
+			// TODO(crawshaw): use single Ref for null.
+			if (next == Integer.MAX_VALUE) {
+				throw new RuntimeException("createRef overflow for " + o);
+			}
+			int refnum = next++;
+			Ref ref = new Ref(refnum, o);
+			javaObjs.put(refnum, ref);
+			return ref;
+		}
+
+		// get returns an existing Ref to either a Java or Go object.
+		// It may be the first time we have seen the Go object.
+		synchronized Ref get(int refnum) {
+			if (refnum > 0) {
+				Ref ref = javaObjs.get(refnum);
+				if (ref == null) {
+					throw new RuntimeException("unknown java Ref: "+refnum);
+				}
+				return ref;
+			}
+			return new Ref(refnum, null);
+		}
+	}
 }

BIN
AndroidLibrary/libgojni.so


+ 7 - 5
AndroidLibrary/psi/psi.go

@@ -75,9 +75,11 @@ func Start(configJson string, listener Listener) error {
 }
 
 func Stop() {
-	close(shutdownBroadcast)
-	controllerWaitGroup.Wait()
-	controller = nil
-	shutdownBroadcast = nil
-	controllerWaitGroup = nil
+	if controller != nil {
+		close(shutdownBroadcast)
+		controllerWaitGroup.Wait()
+		controller = nil
+		shutdownBroadcast = nil
+		controllerWaitGroup = nil
+	}
 }

+ 1 - 1
ConsoleClient/psiphonClient.go

@@ -21,7 +21,7 @@ package main
 
 import (
 	"flag"
-	psiphon "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 	"io/ioutil"
 	"log"
 	"os"