#![cfg(target_os = "android")]
use crate::{ArgProxy, ArgVerbosity, Config, LIB_NAME, main_entry};
use jni::{
JNIEnv,
objects::{JClass, JString},
sys::{jboolean, jint},
};
static TUN_QUIT: std::sync::Mutex<Option<tokio_util::sync::CancellationToken>> = std::sync::Mutex::new(None);
#[unsafe(no_mangle)]
pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Dns2socks_start(
mut env: JNIEnv,
_clazz: JClass,
listen_addr: JString,
dns_remote_server: JString,
socks5_settings: JString,
force_tcp: jboolean,
cache_records: jboolean,
verbosity: jint,
timeout: jint,
) -> jint {
let verbosity: ArgVerbosity = verbosity.try_into().unwrap_or_default();
let filter_str = &format!("off,{LIB_NAME}={verbosity}");
let filter = android_logger::FilterBuilder::new().parse(filter_str).build();
android_logger::init_once(
android_logger::Config::default()
.with_tag("dns2socks")
.with_max_level(log::LevelFilter::Trace)
.with_filter(filter),
);
let listen_addr = match get_java_string(&mut env, &listen_addr) {
Ok(addr) => addr,
Err(_e) => "0.0.0.0:53".to_string(),
};
let dns_remote_server = match get_java_string(&mut env, &dns_remote_server) {
Ok(addr) => addr,
Err(_e) => "8.8.8.8:53".to_string(),
};
let socks5_settings = match get_java_string(&mut env, &socks5_settings) {
Ok(addr) => addr,
Err(_e) => "socks5://127.0.0.1:1080".to_string(),
};
let force_tcp = force_tcp != 0;
let cache_records = cache_records != 0;
let timeout = if timeout < 3 { 5 } else { timeout as u64 };
let shutdown_token = tokio_util::sync::CancellationToken::new();
if let Ok(mut lock) = TUN_QUIT.lock() {
if lock.is_some() {
return -1;
}
*lock = Some(shutdown_token.clone());
} else {
return -2;
}
let main_loop = async move {
let mut cfg = Config::default();
cfg.verbosity(verbosity)
.timeout(timeout)
.force_tcp(force_tcp)
.cache_records(cache_records)
.listen_addr(listen_addr.parse()?)
.dns_remote_server(dns_remote_server.parse()?)
.socks5_settings(ArgProxy::try_from(socks5_settings.as_str())?);
if let Err(err) = main_entry(cfg, shutdown_token).await {
log::error!("main loop error: {}", err);
return Err(err);
}
Ok(())
};
match tokio::runtime::Builder::new_multi_thread().enable_all().build() {
Err(_e) => -3,
Ok(rt) => match rt.block_on(main_loop) {
Ok(_) => 0,
Err(_e) => -4,
},
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Dns2socks_stop(_env: JNIEnv, _: JClass) -> jint {
if let Ok(mut lock) = TUN_QUIT.lock()
&& let Some(shutdown_token) = lock.take()
{
shutdown_token.cancel();
return 0;
}
-1
}
fn get_java_string(env: &mut JNIEnv, string: &JString) -> std::io::Result<String> {
use std::io::{Error, ErrorKind::Other};
Ok(env.get_string(string).map_err(|e| Error::new(Other, e))?.into())
}