Skip to content

Commit

Permalink
Merge pull request #25 from Sifir-io/feature/socket-timeouts
Browse files Browse the repository at this point in the history
Feature/socket timeouts
  • Loading branch information
gabidi authored Apr 22, 2021
2 parents a32b524 + c8b1077 commit a940ad5
Show file tree
Hide file tree
Showing 15 changed files with 506 additions and 139 deletions.
Binary file modified android/libs/sifir_android.aar
Binary file not shown.
3 changes: 2 additions & 1 deletion android/src/main/java/com/reactnativetor/TcpStreamStart.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import com.sifir.tor.TorServiceParam
class TcpStreamStart constructor(
private val target: String,
private val proxy:String,
private val timeoutMs:Long,
private val onSuccess: (stream: TcpSocksStream) -> Unit,
private val onError: (e: Throwable) -> Unit
) {
fun run() {
try {
val stream = TcpSocksStream(target,proxy);
val stream = TcpSocksStream(target,proxy,timeoutMs);
onSuccess(stream);
} catch (e: Error) {
Log.d("TorBridge:TcpStream", "error $e")
Expand Down
66 changes: 35 additions & 31 deletions android/src/main/java/com/reactnativetor/TorModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,29 @@ import okhttp3.OkHttpClient
import java.io.IOException
import java.net.InetSocketAddress
import java.net.ServerSocket
import java.util.concurrent.TimeUnit
import java.net.Proxy;
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.UUID;
import java.util.concurrent.*


/**
* Wraps DataObserver interface into event emitter
* Sent across FFI and will emit on data based on target-data or target-error topic
*/
class DataObserverEmitter(
private val target: String,
private val connId: String,
private val reactContext: ReactApplicationContext,
private val streams: HashMap<String, TcpSocksStream>
) : DataObserver {
override fun onData(p0: String?) {
reactContext
.getJSModule(RCTDeviceEventEmitter::class.java)
.emit("$target-data", p0)
.emit("$connId-data", p0)
}

override fun onError(p0: String?) {
Expand All @@ -40,15 +40,15 @@ class DataObserverEmitter(
// TODO Change this when we implement streaming streams.
if (p0 == "EOF") {
try {
Log.d("TorBridge", "DataObserver: EOF detected from '$target', deleting stream..")
streams.remove(target)?.delete();
Log.d("TorBridge", "DataObserver: EOF detected from '$connId', deleting stream..")
streams.remove(connId)?.delete();
} catch (e: Exception) {
Log.d("TorBridge", "DataObserver:Error deleting stream for '$target': $e")
Log.d("TorBridge", "DataObserver:Error deleting stream for '$connId': $e")
}
}
reactContext
.getJSModule(RCTDeviceEventEmitter::class.java)
.emit("$target-error", p0)
.emit("$connId-error", p0)
}
}

Expand All @@ -57,7 +57,9 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
private var proxy: Proxy? = null;
private var _starting: Boolean = false;
private var _streams: HashMap<String, TcpSocksStream> = HashMap();
private val executorService: ExecutorService = Executors.newFixedThreadPool(4)
// private val executorService: ExecutorService = Executors.newFixedThreadPool(4)
private val executorService : ThreadPoolExecutor = ThreadPoolExecutor(4,4, 0L, TimeUnit.MILLISECONDS, LinkedBlockingQueue<Runnable>());


/**
* Gets a client that accepts all SSL certs
Expand Down Expand Up @@ -142,15 +144,15 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
val task = TorBridgeRequest(promise, client, param);
task.run()
} catch (e: Exception) {
Log.d("TorBridge", "error on sendRequest$e")
Log.d("TorBridge", "error on request: $e")
promise.reject(e)
}
}
}


@ReactMethod
fun startDaemon(promise: Promise) {
fun startDaemon(timeoutMs: Double, promise: Promise) {
if (service != null) {
promise.reject(Throwable("Service already running, call stopDaemon first"))
}
Expand All @@ -161,7 +163,7 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
executorService.execute {
val socksPort = findFreePort();
val path = this.reactApplicationContext.cacheDir.toString();
val param = StartParam(socksPort, path)
val param = StartParam(socksPort, path, timeoutMs.toLong())
try {
TorBridgeStartAsync(param, {
service = it
Expand All @@ -174,7 +176,7 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
}).run();

} catch (e: Exception) {
Log.d("TorBridge", "error on sendRequest$e")
Log.d("TorBridge", "error on startDaemon: $e")
promise.reject(e)
}
}
Expand Down Expand Up @@ -209,55 +211,57 @@ class TorModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
}

@ReactMethod
fun startTcpConn(target: String, promise: Promise) {
fun startTcpConn(target: String, timeoutMs: Double, promise: Promise) {
executorService.execute {
try {
if (service == null) {
throw Exception("Tor service not running, call startDaemon first")
}
TcpStreamStart(target, "0.0.0.0:${service?.socksPort}", {
it.on_data(DataObserverEmitter(target, this.reactApplicationContext, _streams));
_streams.set(target, it);
promise.resolve(true);
TcpStreamStart(target, "0.0.0.0:${service?.socksPort}", timeoutMs.toLong(), {
// Assign UUID to connection to manage it
val uuid = UUID.randomUUID();
val connId = uuid.toString();
it.on_data(DataObserverEmitter(connId, this.reactApplicationContext, _streams));
_streams.set(connId, it);
Log.d("TorBridge", "Connection to $target created and assigned connection Id $connId");
promise.resolve(connId);
}, {
Log.d("TorBridge", "error on startTcpConn$it")
Log.d("TorBridge", "error on startTcpConn: $it")
promise.reject(it)
}).run();
} catch (e: Exception) {
Log.d("TorBridge", "error on startTcpConn$e")
Log.d("TorBridge", "error on startTcpConn: $e")
promise.reject(e)
}
}
}

@ReactMethod
fun sendTcpConnMsg(target: String, msg: String, timeoutSec: Double, promise: Promise) {
fun sendTcpConnMsg(connId: String, msg: String, timeoutSec: Double, promise: Promise) {
try {
if (service == null) {
throw Throwable("Tor Service not running, call startDaemon first")
}
var stream = _streams.get(target);
if (stream == null) {
throw Throwable("Stream for target is not initialized, call startTcpConn first");
}
var stream = _streams[connId]
?: throw Throwable("Stream for connectionId $connId is not initialized, call startTcpConn first");
stream.send_data(msg, timeoutSec.toLong());
promise.resolve(true);
} catch (e: Exception) {
Log.d("TorBridge", "error on sendTcpConnMsg$e")
Log.d("TorBridge", "error on sendTcpConnMsg on connection Id $connId : $e")
promise.reject(e)
} catch (e: Throwable) {
Log.d("TorBridge", "error on sendTcpConnMsg$e")
Log.d("TorBridge", "error on sendTcpConnMsg on connection ID $connId : $e")
promise.reject(e)
}
}

@ReactMethod
fun stopTcpConn(target: String, promise: Promise) {
fun stopTcpConn(connId: String, promise: Promise) {
try {
_streams.remove(target)?.delete();
_streams.remove(connId)?.delete();
promise.resolve(true);
} catch (e: Exception) {
Log.d("TorBridge", "error on stopTcpConn$e")
Log.d("TorBridge", "error on stopTcpConn for connection Id $connId : $e")
promise.reject(e)
}
}
Expand Down
8 changes: 5 additions & 3 deletions android/src/main/java/com/reactnativetor/TorStartAsync.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import com.sifir.tor.TorServiceParam

class StartParam(
val socksPort: Int,
var path: String
var path: String,
val timeoutMs: Long
);

class TorBridgeStartAsync constructor(
Expand All @@ -19,9 +20,10 @@ class TorBridgeStartAsync constructor(
) {
fun run() {
try {
val ownedTor = OwnedTorService(TorServiceParam(param.path, param.socksPort));
Log.d("TorBridge", "Starting Tor with ${param.path} ${param.socksPort} ${param.timeoutMs}")
val ownedTor = OwnedTorService(TorServiceParam(param.path, param.socksPort,param.timeoutMs));
onSuccess(ownedTor);
} catch (e: Error) {
} catch (e: Exception) {
Log.d("TorBridge:StartAsync", "error onPostExecute$e")
onError(e as Throwable);
}
Expand Down
19 changes: 0 additions & 19 deletions example/ios/TorExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
BF42A7D72DA58672CCAA6EE3 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
Expand Down Expand Up @@ -206,24 +205,6 @@
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
BF42A7D72DA58672CCAA6EE3 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-TorExample/Pods-TorExample-frameworks.sh",
"${PODS_ROOT}/../../../ios/Libsifir_ios.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Libsifir_ios.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TorExample/Pods-TorExample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
DDE0C70ACB6DE4C37B3B4C4C /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down
Loading

0 comments on commit a940ad5

Please sign in to comment.