reorganize tor package

This commit is contained in:
Fabian Freund
2025-09-29 11:11:32 +02:00
parent 8558248dfa
commit 6b71d35e5e
8 changed files with 328 additions and 740 deletions
@@ -0,0 +1,558 @@
// AUTO GENERATED FILE, DO NOT EDIT.
//
// Generated by `package:ffigen`.
// ignore_for_file: type=lint
import 'dart:ffi' as ffi;
class NativeLibrary {
/// Holds the symbol lookup function.
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
_lookup;
/// The symbols are looked up in [dynamicLibrary].
NativeLibrary(ffi.DynamicLibrary dynamicLibrary)
: _lookup = dynamicLibrary.lookup;
/// The symbols are looked up with [lookup].
NativeLibrary.fromLookup(
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName) lookup,
) : _lookup = lookup;
Tor tor_start(
int socks_port,
ffi.Pointer<ffi.Char> state_dir,
ffi.Pointer<ffi.Char> cache_dir,
int obfs4_port,
int snowflake_port,
ffi.Pointer<ffi.Char> bridge_lines,
) {
return _tor_start(
socks_port,
state_dir,
cache_dir,
obfs4_port,
snowflake_port,
bridge_lines,
);
}
late final _tor_startPtr =
_lookup<
ffi.NativeFunction<
Tor Function(
ffi.Uint16,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Uint16,
ffi.Uint16,
ffi.Pointer<ffi.Char>,
)
>
>('tor_start');
late final _tor_start = _tor_startPtr
.asFunction<
Tor Function(
int,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
int,
int,
ffi.Pointer<ffi.Char>,
)
>();
bool tor_reconfigure(
ffi.Pointer<ffi.Void> client,
ffi.Pointer<ffi.Char> state_dir,
ffi.Pointer<ffi.Char> cache_dir,
int obfs4_port,
int snowflake_port,
ffi.Pointer<ffi.Char> bridge_lines,
) {
return _tor_reconfigure(
client,
state_dir,
cache_dir,
obfs4_port,
snowflake_port,
bridge_lines,
);
}
late final _tor_reconfigurePtr =
_lookup<
ffi.NativeFunction<
ffi.Bool Function(
ffi.Pointer<ffi.Void>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Uint16,
ffi.Uint16,
ffi.Pointer<ffi.Char>,
)
>
>('tor_reconfigure');
late final _tor_reconfigure = _tor_reconfigurePtr
.asFunction<
bool Function(
ffi.Pointer<ffi.Void>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
int,
int,
ffi.Pointer<ffi.Char>,
)
>();
bool tor_client_bootstrap(ffi.Pointer<ffi.Void> client) {
return _tor_client_bootstrap(client);
}
late final _tor_client_bootstrapPtr =
_lookup<ffi.NativeFunction<ffi.Bool Function(ffi.Pointer<ffi.Void>)>>(
'tor_client_bootstrap',
);
late final _tor_client_bootstrap = _tor_client_bootstrapPtr
.asFunction<bool Function(ffi.Pointer<ffi.Void>)>();
void tor_client_set_dormant(ffi.Pointer<ffi.Void> client, bool soft_mode) {
return _tor_client_set_dormant(client, soft_mode);
}
late final _tor_client_set_dormantPtr =
_lookup<
ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Bool)>
>('tor_client_set_dormant');
late final _tor_client_set_dormant = _tor_client_set_dormantPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>, bool)>();
void tor_proxy_stop(ffi.Pointer<ffi.Void> proxy) {
return _tor_proxy_stop(proxy);
}
late final _tor_proxy_stopPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
'tor_proxy_stop',
);
late final _tor_proxy_stop = _tor_proxy_stopPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
void tor_hello() {
return _tor_hello();
}
late final _tor_helloPtr = _lookup<ffi.NativeFunction<ffi.Void Function()>>(
'tor_hello',
);
late final _tor_hello = _tor_helloPtr.asFunction<void Function()>();
ffi.Pointer<ffi.Char> tor_last_error_message() {
return _tor_last_error_message();
}
late final _tor_last_error_messagePtr =
_lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
'tor_last_error_message',
);
late final _tor_last_error_message = _tor_last_error_messagePtr
.asFunction<ffi.Pointer<ffi.Char> Function()>();
int tor_get_nofile_limit() {
return _tor_get_nofile_limit();
}
late final _tor_get_nofile_limitPtr =
_lookup<ffi.NativeFunction<ffi.Uint64 Function()>>(
'tor_get_nofile_limit',
);
late final _tor_get_nofile_limit = _tor_get_nofile_limitPtr
.asFunction<int Function()>();
int tor_set_nofile_limit(int limit) {
return _tor_set_nofile_limit(limit);
}
late final _tor_set_nofile_limitPtr =
_lookup<ffi.NativeFunction<ffi.Uint64 Function(ffi.Uint64)>>(
'tor_set_nofile_limit',
);
late final _tor_set_nofile_limit = _tor_set_nofile_limitPtr
.asFunction<int Function(int)>();
}
typedef __u_char = ffi.UnsignedChar;
typedef Dart__u_char = int;
typedef __u_short = ffi.UnsignedShort;
typedef Dart__u_short = int;
typedef __u_int = ffi.UnsignedInt;
typedef Dart__u_int = int;
typedef __u_long = ffi.UnsignedLong;
typedef Dart__u_long = int;
typedef __int8_t = ffi.SignedChar;
typedef Dart__int8_t = int;
typedef __uint8_t = ffi.UnsignedChar;
typedef Dart__uint8_t = int;
typedef __int16_t = ffi.Short;
typedef Dart__int16_t = int;
typedef __uint16_t = ffi.UnsignedShort;
typedef Dart__uint16_t = int;
typedef __int32_t = ffi.Int;
typedef Dart__int32_t = int;
typedef __uint32_t = ffi.UnsignedInt;
typedef Dart__uint32_t = int;
typedef __int64_t = ffi.Long;
typedef Dart__int64_t = int;
typedef __uint64_t = ffi.UnsignedLong;
typedef Dart__uint64_t = int;
typedef __int_least8_t = __int8_t;
typedef __uint_least8_t = __uint8_t;
typedef __int_least16_t = __int16_t;
typedef __uint_least16_t = __uint16_t;
typedef __int_least32_t = __int32_t;
typedef __uint_least32_t = __uint32_t;
typedef __int_least64_t = __int64_t;
typedef __uint_least64_t = __uint64_t;
typedef __quad_t = ffi.Long;
typedef Dart__quad_t = int;
typedef __u_quad_t = ffi.UnsignedLong;
typedef Dart__u_quad_t = int;
typedef __intmax_t = ffi.Long;
typedef Dart__intmax_t = int;
typedef __uintmax_t = ffi.UnsignedLong;
typedef Dart__uintmax_t = int;
typedef __dev_t = ffi.UnsignedLong;
typedef Dart__dev_t = int;
typedef __uid_t = ffi.UnsignedInt;
typedef Dart__uid_t = int;
typedef __gid_t = ffi.UnsignedInt;
typedef Dart__gid_t = int;
typedef __ino_t = ffi.UnsignedLong;
typedef Dart__ino_t = int;
typedef __ino64_t = ffi.UnsignedLong;
typedef Dart__ino64_t = int;
typedef __mode_t = ffi.UnsignedInt;
typedef Dart__mode_t = int;
typedef __nlink_t = ffi.UnsignedLong;
typedef Dart__nlink_t = int;
typedef __off_t = ffi.Long;
typedef Dart__off_t = int;
typedef __off64_t = ffi.Long;
typedef Dart__off64_t = int;
typedef __pid_t = ffi.Int;
typedef Dart__pid_t = int;
final class __fsid_t extends ffi.Struct {
@ffi.Array.multi([2])
external ffi.Array<ffi.Int> __val;
}
typedef __clock_t = ffi.Long;
typedef Dart__clock_t = int;
typedef __rlim_t = ffi.UnsignedLong;
typedef Dart__rlim_t = int;
typedef __rlim64_t = ffi.UnsignedLong;
typedef Dart__rlim64_t = int;
typedef __id_t = ffi.UnsignedInt;
typedef Dart__id_t = int;
typedef __time_t = ffi.Long;
typedef Dart__time_t = int;
typedef __useconds_t = ffi.UnsignedInt;
typedef Dart__useconds_t = int;
typedef __suseconds_t = ffi.Long;
typedef Dart__suseconds_t = int;
typedef __suseconds64_t = ffi.Long;
typedef Dart__suseconds64_t = int;
typedef __daddr_t = ffi.Int;
typedef Dart__daddr_t = int;
typedef __key_t = ffi.Int;
typedef Dart__key_t = int;
typedef __clockid_t = ffi.Int;
typedef Dart__clockid_t = int;
typedef __timer_t = ffi.Pointer<ffi.Void>;
typedef __blksize_t = ffi.Long;
typedef Dart__blksize_t = int;
typedef __blkcnt_t = ffi.Long;
typedef Dart__blkcnt_t = int;
typedef __blkcnt64_t = ffi.Long;
typedef Dart__blkcnt64_t = int;
typedef __fsblkcnt_t = ffi.UnsignedLong;
typedef Dart__fsblkcnt_t = int;
typedef __fsblkcnt64_t = ffi.UnsignedLong;
typedef Dart__fsblkcnt64_t = int;
typedef __fsfilcnt_t = ffi.UnsignedLong;
typedef Dart__fsfilcnt_t = int;
typedef __fsfilcnt64_t = ffi.UnsignedLong;
typedef Dart__fsfilcnt64_t = int;
typedef __fsword_t = ffi.Long;
typedef Dart__fsword_t = int;
typedef __ssize_t = ffi.Long;
typedef Dart__ssize_t = int;
typedef __syscall_slong_t = ffi.Long;
typedef Dart__syscall_slong_t = int;
typedef __syscall_ulong_t = ffi.UnsignedLong;
typedef Dart__syscall_ulong_t = int;
typedef __loff_t = __off64_t;
typedef __caddr_t = ffi.Pointer<ffi.Char>;
typedef __intptr_t = ffi.Long;
typedef Dart__intptr_t = int;
typedef __socklen_t = ffi.UnsignedInt;
typedef Dart__socklen_t = int;
typedef __sig_atomic_t = ffi.Int;
typedef Dart__sig_atomic_t = int;
typedef int_least8_t = __int_least8_t;
typedef int_least16_t = __int_least16_t;
typedef int_least32_t = __int_least32_t;
typedef int_least64_t = __int_least64_t;
typedef uint_least8_t = __uint_least8_t;
typedef uint_least16_t = __uint_least16_t;
typedef uint_least32_t = __uint_least32_t;
typedef uint_least64_t = __uint_least64_t;
typedef int_fast8_t = ffi.SignedChar;
typedef Dartint_fast8_t = int;
typedef int_fast16_t = ffi.Long;
typedef Dartint_fast16_t = int;
typedef int_fast32_t = ffi.Long;
typedef Dartint_fast32_t = int;
typedef int_fast64_t = ffi.Long;
typedef Dartint_fast64_t = int;
typedef uint_fast8_t = ffi.UnsignedChar;
typedef Dartuint_fast8_t = int;
typedef uint_fast16_t = ffi.UnsignedLong;
typedef Dartuint_fast16_t = int;
typedef uint_fast32_t = ffi.UnsignedLong;
typedef Dartuint_fast32_t = int;
typedef uint_fast64_t = ffi.UnsignedLong;
typedef Dartuint_fast64_t = int;
typedef intmax_t = __intmax_t;
typedef uintmax_t = __uintmax_t;
typedef _Float32 = ffi.Float;
typedef Dart_Float32 = double;
typedef _Float64 = ffi.Double;
typedef Dart_Float64 = double;
typedef _Float32x = ffi.Double;
typedef Dart_Float32x = double;
typedef u_char = __u_char;
typedef u_short = __u_short;
typedef u_int = __u_int;
typedef u_long = __u_long;
typedef quad_t = __quad_t;
typedef u_quad_t = __u_quad_t;
typedef fsid_t = __fsid_t;
typedef loff_t = __loff_t;
typedef ino_t = __ino_t;
typedef dev_t = __dev_t;
typedef gid_t = __gid_t;
typedef mode_t = __mode_t;
typedef nlink_t = __nlink_t;
typedef uid_t = __uid_t;
typedef off_t = __off_t;
typedef pid_t = __pid_t;
typedef id_t = __id_t;
typedef ssize_t = __ssize_t;
typedef daddr_t = __daddr_t;
typedef caddr_t = __caddr_t;
typedef key_t = __key_t;
typedef clock_t = __clock_t;
typedef clockid_t = __clockid_t;
typedef time_t = __time_t;
typedef timer_t = __timer_t;
typedef ulong = ffi.UnsignedLong;
typedef Dartulong = int;
typedef ushort = ffi.UnsignedShort;
typedef Dartushort = int;
typedef uint = ffi.UnsignedInt;
typedef Dartuint = int;
typedef u_int8_t = __uint8_t;
typedef u_int16_t = __uint16_t;
typedef u_int32_t = __uint32_t;
typedef u_int64_t = __uint64_t;
typedef register_t = ffi.Long;
typedef Dartregister_t = int;
final class __sigset_t extends ffi.Struct {
@ffi.Array.multi([16])
external ffi.Array<ffi.UnsignedLong> __val;
}
typedef sigset_t = __sigset_t;
typedef suseconds_t = __suseconds_t;
typedef __fd_mask = ffi.Long;
typedef Dart__fd_mask = int;
typedef fd_mask = __fd_mask;
typedef blksize_t = __blksize_t;
typedef blkcnt_t = __blkcnt_t;
typedef fsblkcnt_t = __fsblkcnt_t;
typedef fsfilcnt_t = __fsfilcnt_t;
final class __pthread_internal_list extends ffi.Struct {
external ffi.Pointer<__pthread_internal_list> __prev;
external ffi.Pointer<__pthread_internal_list> __next;
}
typedef __pthread_list_t = __pthread_internal_list;
final class __pthread_internal_slist extends ffi.Struct {
external ffi.Pointer<__pthread_internal_slist> __next;
}
typedef __pthread_slist_t = __pthread_internal_slist;
typedef __tss_t = ffi.UnsignedInt;
typedef Dart__tss_t = int;
typedef __thrd_t = ffi.UnsignedLong;
typedef Dart__thrd_t = int;
typedef pthread_t = ffi.UnsignedLong;
typedef Dartpthread_t = int;
typedef pthread_key_t = ffi.UnsignedInt;
typedef Dartpthread_key_t = int;
typedef pthread_once_t = ffi.Int;
typedef Dartpthread_once_t = int;
typedef __compar_fn_tFunction =
ffi.Int Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>);
typedef Dart__compar_fn_tFunction =
int Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>);
typedef __compar_fn_t = ffi.Pointer<ffi.NativeFunction<__compar_fn_tFunction>>;
final class Tor extends ffi.Struct {
external ffi.Pointer<ffi.Void> client;
external ffi.Pointer<ffi.Void> proxy;
}
const int true$ = 1;
const int false$ = 0;
const int INT8_MIN = -128;
const int INT16_MIN = -32768;
const int INT32_MIN = -2147483648;
const int INT64_MIN = -9223372036854775808;
const int INT8_MAX = 127;
const int INT16_MAX = 32767;
const int INT32_MAX = 2147483647;
const int INT64_MAX = 9223372036854775807;
const int UINT8_MAX = 255;
const int UINT16_MAX = 65535;
const int UINT32_MAX = 4294967295;
const int UINT64_MAX = -1;
const int INT_LEAST8_MIN = -128;
const int INT_LEAST16_MIN = -32768;
const int INT_LEAST32_MIN = -2147483648;
const int INT_LEAST64_MIN = -9223372036854775808;
const int INT_LEAST8_MAX = 127;
const int INT_LEAST16_MAX = 32767;
const int INT_LEAST32_MAX = 2147483647;
const int INT_LEAST64_MAX = 9223372036854775807;
const int UINT_LEAST8_MAX = 255;
const int UINT_LEAST16_MAX = 65535;
const int UINT_LEAST32_MAX = 4294967295;
const int UINT_LEAST64_MAX = -1;
const int INT_FAST8_MIN = -128;
const int INT_FAST16_MIN = -9223372036854775808;
const int INT_FAST32_MIN = -9223372036854775808;
const int INT_FAST64_MIN = -9223372036854775808;
const int INT_FAST8_MAX = 127;
const int INT_FAST16_MAX = 9223372036854775807;
const int INT_FAST32_MAX = 9223372036854775807;
const int INT_FAST64_MAX = 9223372036854775807;
const int UINT_FAST8_MAX = 255;
const int UINT_FAST16_MAX = -1;
const int UINT_FAST32_MAX = -1;
const int UINT_FAST64_MAX = -1;
const int INTPTR_MIN = -9223372036854775808;
const int INTPTR_MAX = 9223372036854775807;
const int UINTPTR_MAX = -1;
const int INTMAX_MIN = -9223372036854775808;
const int INTMAX_MAX = 9223372036854775807;
const int UINTMAX_MAX = -1;
const int PTRDIFF_MIN = -9223372036854775808;
const int PTRDIFF_MAX = 9223372036854775807;
const int SIG_ATOMIC_MIN = -2147483648;
const int SIG_ATOMIC_MAX = 2147483647;
const int SIZE_MAX = -1;
const int WCHAR_MIN = -2147483648;
const int WCHAR_MAX = 2147483647;
const int WINT_MIN = 0;
const int WINT_MAX = 4294967295;
const int NULL = 0;
const int WNOHANG = 1;
const int WUNTRACED = 2;
const int WSTOPPED = 2;
const int WEXITED = 4;
const int WCONTINUED = 8;
const int WNOWAIT = 16777216;
const int RAND_MAX = 2147483647;
const int EXIT_FAILURE = 1;
const int EXIT_SUCCESS = 0;
const int LITTLE_ENDIAN = 1234;
const int BIG_ENDIAN = 4321;
const int PDP_ENDIAN = 3412;
const int BYTE_ORDER = 1234;
const int FD_SETSIZE = 1024;
const int NFDBITS = 64;
+325
View File
@@ -0,0 +1,325 @@
// SPDX-FileCopyrightText: 2022 Foundation Devices Inc.
// SPDX-FileCopyrightText: 2024 Foundation Devices Inc.
//
// SPDX-License-Identifier: MIT
import 'dart:async';
import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tor/src/generated_bindings.dart' as rust;
DynamicLibrary load(String name) {
if (Platform.isAndroid || Platform.isLinux) {
return DynamicLibrary.open('lib$name.so');
} else if (Platform.isIOS || Platform.isMacOS) {
return DynamicLibrary.open('$name.framework/$name');
} else if (Platform.isWindows) {
return DynamicLibrary.open('$name.dll');
} else {
throw NotSupportedPlatform('${Platform.operatingSystem} is not supported!');
}
}
class CouldntBootstrapDirectory implements Exception {
String? rustError;
CouldntBootstrapDirectory({this.rustError});
}
class NotSupportedPlatform implements Exception {
String reason;
NotSupportedPlatform(this.reason);
}
class ClientNotActive implements Exception {}
class Tor {
static const String libName = "tor";
static late DynamicLibrary _lib;
Pointer<Void> _clientPtr = nullptr;
Pointer<Void> _proxyPtr = nullptr;
/// Flag to indicate that Tor client and proxy have started. Traffic is routed through the proxy only if it is also [enabled].
bool get started => _proxyPort > -1;
bool get hasClient => _clientPtr != nullptr;
/// Flag to indicate that traffic should flow through the proxy.
bool _enabled = false;
/// Getter for the enabled flag.
bool get enabled => _enabled;
/// Flag to indicate that a Tor circuit is thought to have been established
/// (true means that Tor has bootstrapped).
bool get bootstrapped => _bootstrapped;
/// Getter for the bootstrapped flag.
bool _bootstrapped = false;
/// A stream of Tor events.
///
/// This stream broadcast just the port for now (-1 if circuit not established or proxy not enabled)
final StreamController events = StreamController.broadcast();
/// Getter for the proxy port.
///
/// Returns -1 if Tor is not enabled or if the circuit is not established.
///
/// Returns the proxy port if Tor is enabled and the circuit is established.
///
/// This is the port that should be used for all requests.
int get port {
if (!_enabled) {
return -1;
}
return _proxyPort;
}
/// The proxy port.
int _proxyPort = -1;
/// Singleton instance of the Tor class.
static final Tor _instance = Tor._internal();
/// Getter for the singleton instance of the Tor class.
static Tor get instance => _instance;
/// Initialize the Tor ffi lib instance if it hasn't already been set. Nothing
/// changes if _tor is already been set.
///
/// Returns a Future that completes when the Tor service has started.
///
/// Throws an exception if the Tor service fails to start.
static Tor init({bool enabled = true}) {
final singleton = Tor._instance;
singleton._enabled = enabled;
return singleton;
}
/// Private constructor for the Tor class.
Tor._internal() {
_lib = load(libName);
if (kDebugMode) {
print("Instance of Tor created!");
}
}
void broadcastState() {
events.add(port);
}
Future<int> _getRandomUnusedPort({List<int> excluded = const []}) async {
final random = Random.secure();
int potentialPort = 0;
retry:
while (potentialPort <= 0 || excluded.contains(potentialPort)) {
potentialPort = random.nextInt(65535);
try {
final socket = await ServerSocket.bind("0.0.0.0", potentialPort);
await socket.close();
return potentialPort;
} catch (_) {
continue retry;
}
}
return -1;
}
/// Start the Tor service.
///
/// This will start the Tor service and establish a Tor circuit.
///
/// Throws an exception if the Tor service fails to start.
///
/// Returns a Future that completes when the Tor service has started.
Future<void> start({
int? obfs4Port,
int? snowflakePort,
String? bridgeLines,
}) async {
broadcastState();
// Set the state and cache directories.
final Directory appSupportDir = await getApplicationSupportDirectory();
final stateDir = await Directory(
'${appSupportDir.path}/tor_state',
).create();
final cacheDir = await Directory(
'${appSupportDir.path}/tor_cache',
).create();
// Generate a random port.
final newPort = await _getRandomUnusedPort();
// Start the Tor service in an isolate.
final tor = await Isolate.run(() {
// Load the Tor library.
final lib = rust.NativeLibrary(load(libName));
// Start the Tor service.
final tor = lib.tor_start(
newPort,
stateDir.path.toNativeUtf8() as Pointer<Char>,
cacheDir.path.toNativeUtf8() as Pointer<Char>,
obfs4Port ?? -1,
snowflakePort ?? -1,
bridgeLines?.toNativeUtf8() as Pointer<Char>? ?? nullptr,
);
// Throw an exception if the Tor service fails to start.
if (tor.client == nullptr) {
throwRustException(lib);
}
return tor;
});
// Set the client pointer and started flag.
_clientPtr = Pointer.fromAddress(tor.client.address);
_proxyPtr = Pointer.fromAddress(tor.proxy.address);
// Bootstrap the Tor service.
bootstrap();
// Set the proxy port.
_proxyPort = newPort;
broadcastState();
}
Future<void> reconfigure({
int? obfs4Port,
int? snowflakePort,
String? bridgeLines,
}) async {
final lib = rust.NativeLibrary(_lib);
// Set the state and cache directories.
final Directory appSupportDir = await getApplicationSupportDirectory();
final stateDir = await Directory(
'${appSupportDir.path}/tor_state',
).create();
final cacheDir = await Directory(
'${appSupportDir.path}/tor_cache',
).create();
final reconfigured = lib.tor_reconfigure(
_clientPtr,
stateDir.path.toNativeUtf8() as Pointer<Char>,
cacheDir.path.toNativeUtf8() as Pointer<Char>,
obfs4Port ?? -1,
snowflakePort ?? -1,
bridgeLines?.toNativeUtf8() as Pointer<Char>? ?? nullptr,
);
if (!reconfigured) {
throwRustException(lib);
}
}
/// Bootstrap the Tor service.
///
/// This will bootstrap the Tor service and establish a Tor circuit. This
/// function should only be called after the Tor service has been started.
///
/// This function will block until the Tor service has bootstrapped.
///
/// Throws an exception if the Tor service fails to bootstrap.
///
/// Returns void.
void bootstrap() {
// Load the Tor library.
final lib = rust.NativeLibrary(_lib);
// Bootstrap the Tor service.
_bootstrapped = lib.tor_client_bootstrap(_clientPtr);
// Throw an exception if the Tor service fails to bootstrap.
if (!bootstrapped) {
throwRustException(lib);
}
}
/// Prevent traffic flowing through the proxy
void disable() {
stop();
_enabled = false;
broadcastState();
}
/// Stops the proxy
void stop() {
final lib = rust.NativeLibrary(_lib);
if (_proxyPtr != nullptr) {
lib.tor_proxy_stop(_proxyPtr);
_proxyPtr = nullptr;
_bootstrapped = false;
_proxyPort = -1;
broadcastState();
}
}
void setClientDormant(bool dormant) {
if (_clientPtr == nullptr || !started || !bootstrapped) {
throw ClientNotActive();
}
final lib = rust.NativeLibrary(_lib);
lib.tor_client_set_dormant(_clientPtr, dormant);
}
Future<void> isReady() async {
return await Future.doWhile(
() => Future.delayed(const Duration(seconds: 1)).then((_) {
// We are waiting and making absolutely no request unless:
// Tor is disabled
if (!enabled) {
return false;
}
// ...or Tor circuit is established
if (bootstrapped) {
return false;
}
// This way we avoid making clearnet req's while Tor is initialising
return true;
}),
);
}
static void throwRustException(rust.NativeLibrary lib) {
final String rustError = lib
.tor_last_error_message()
.cast<Utf8>()
.toDartString();
throw _getRustException(rustError);
}
static Exception _getRustException(String rustError) {
if (rustError.contains('Unable to bootstrap a working directory')) {
return CouldntBootstrapDirectory(rustError: rustError);
} else {
return Exception(rustError);
}
}
void hello() {
rust.NativeLibrary(_lib).tor_hello();
}
}