#![cfg(target_os = "android")]
use crate::{
Args,
error::{Error, Result},
};
use jni::{
Env, EnvUnowned,
objects::{JClass, JString},
sys::{jchar, jint},
};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run(
mut env: EnvUnowned<'_>,
_clazz: JClass<'_>,
cli_args: JString<'_>,
tun_mtu: jchar,
) -> jint {
env.with_env(|env: &mut Env| -> Result<jint> {
let cli_args = get_java_string(env, &cli_args)?;
let tokens = shlex::split(&cli_args).ok_or_else(|| Error::from("Failed to split CLI args"))?;
let tokens_clone = tokens.clone();
let args = <Args as ::clap::Parser>::try_parse_from(tokens).map_err(|err| Error::from(format!("Parse CLI args: {err}")))?;
let filter_str = format!("off,tun2proxy={}", args.verbosity);
let filter = android_logger::FilterBuilder::new().parse(&filter_str).build();
android_logger::init_once(
android_logger::Config::default()
.with_tag("tun2proxy")
.with_max_level(log::LevelFilter::Trace)
.with_filter(filter),
);
if !tokens_clone
.iter()
.any(|token| token == "--dns" || token.starts_with("--dns=") || token == "-d" || token.starts_with("-d"))
{
log::error!("--dns is required for Android");
return Err(Error::from("--dns is required for Android"));
}
if args.tun_fd.is_none() {
log::error!("tun_fd is required for Android");
return Err(Error::from("tun_fd is required for Android"));
}
let v = crate::general_api::general_run_for_api(args, tun_mtu, false);
Ok::<jint, Error>(v)
})
.resolve::<jni::errors::LogErrorAndDefault>()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_stop(_env: EnvUnowned<'_>, _: JClass<'_>) -> jint {
crate::general_api::tun2proxy_stop_internal()
}
fn get_java_string(env: &Env, string: &JString) -> Result<String, Error> {
string.try_to_string(env).map_err(|e| e.into())
}