diff --git a/.cargo/config.toml b/.cargo/config.toml index a92f80e..99b3ae2 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,6 +5,16 @@ rustflags = ["-C", "linker-flavor=ld.lld"] [target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc" +[target.aarch64-unknown-linux-ohos] +ar = "/usr/local/ohos-sdk/linux/native/llvm/bin/llvm-ar" +linker = "/home/runner/sdk/native/llvm/aarch64-unknown-linux-ohos-clang.sh" + +[target.aarch64-unknown-linux-ohos.env] +PKG_CONFIG_PATH = "/usr/local/ohos-sdk/linux/native/sysroot/usr/lib/pkgconfig:/usr/local/ohos-sdk/linux/native/sysroot/usr/local/lib/pkgconfig" +PKG_CONFIG_LIBDIR = "/usr/local/ohos-sdk/linux/native/sysroot/usr/lib:/usr/local/ohos-sdk/linux/native/sysroot/usr/local/lib" +PKG_CONFIG_SYSROOT_DIR = "/usr/local/ohos-sdk/linux/native/sysroot" +SYSROOT = "/usr/local/ohos-sdk/linux/native/sysroot" + [target.aarch64-unknown-linux-musl] linker = "aarch64-unknown-linux-musl-gcc" rustflags = ["-C", "target-feature=+crt-static"] diff --git a/.github/workflows/ohos.yml b/.github/workflows/ohos.yml new file mode 100644 index 0000000..ac7993d --- /dev/null +++ b/.github/workflows/ohos.yml @@ -0,0 +1,111 @@ +name: EasyTier OHOS + +on: + push: + branches: ["develop", "main", "releases/**"] + pull_request: + branches: ["develop", "main"] + +env: + CARGO_TERM_COLOR: always + +defaults: + run: + # necessary for windows + shell: bash + +jobs: + pre_job: + # continue-on-error: true # Uncomment once integration is finished + runs-on: ubuntu-latest + # Map a step output to a job output + outputs: + # do not skip push on branch starts with releases/ + should_skip: ${{ steps.skip_check.outputs.should_skip == 'true' && !startsWith(github.ref_name, 'releases/') }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # All of these options are optional, so you can remove them if you are happy with the defaults + concurrent_skipping: 'same_content_newer' + skip_after_successful_duplicate: 'true' + cancel_others: 'true' + paths: '["Cargo.toml", "Cargo.lock", "easytier/**", "easytier-contrib/easytier-ohrs/**", ".github/workflows/ohos.yml", ".github/workflows/install_rust.sh"]' + build-ohos: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + wget \ + unzip \ + git \ + pkg-config + sudo apt-get clean + + - name: Download and extract native SDK + working-directory: ../../../ + run: | + echo $PWD + wget -q \ + https://github.com/openharmony-rs/ohos-sdk/releases/download/v5.1.0/ohos-sdk-windows_linux-public.tar.gz.aa + wget -q \ + https://github.com/openharmony-rs/ohos-sdk/releases/download/v5.1.0/ohos-sdk-windows_linux-public.tar.gz.ab + cat ohos-sdk-windows_linux-public.tar.gz.aa ohos-sdk-windows_linux-public.tar.gz.ab > sdk.tar.gz + echo "Extracting native..." + mkdir sdk + tar -xzf sdk.tar.gz ohos-sdk/linux/native-linux-x64-5.1.0.107-Release.zip + tar -xzf sdk.tar.gz ohos-sdk/linux/toolchains-linux-x64-5.1.0.107-Release.zip + unzip -qq ohos-sdk/linux/native-linux-x64-5.1.0.107-Release.zip -d sdk + unzip -qq ohos-sdk/linux/toolchains-linux-x64-5.1.0.107-Release.zip -d sdk + ls -la sdk/native/llvm/bin/ + rm -rf ohos-sdk-windows_linux-public.tar.gz.aa ohos-sdk-windows_linux-public.tar.gz.ab ohos-sdk/ + + - name: Download and Extract Custom SDK + run: | + wget https://github.com/FrankHan052176/Easytier-OHOS-sdk/releases/download/v1/ohos-sdk.zip -O /tmp/ohos-sdk.zip + sudo unzip -o /tmp/ohos-sdk.zip -d /tmp/custom-sdk + sudo cp -rf /tmp/custom-sdk/linux/native/* $HOME/sdk/native + echo "Custom SDK files deployed to $HOME/sdk/native" + ls -a $HOME/sdk/native + + - name: Setup build environment + run: | + echo "OHOS_NDK_HOME=$HOME/sdk" >> $GITHUB_ENV + echo "TARGET_ARCH=aarch64-linux-ohos" >> $GITHUB_ENV + + - name: Create clang wrapper script + run: | + sudo mkdir -p $OHOS_NDK_HOME/native/llvm + sudo tee $OHOS_NDK_HOME/native/llvm/aarch64-unknown-linux-ohos-clang.sh > /dev/null <<'EOF' + #!/bin/sh + exec $OHOS_NDK_HOME/native/llvm/bin/clang \ + -target aarch64-linux-ohos \ + --sysroot=$OHOS_NDK_HOME/native/sysroot \ + -D__MUSL__ \ + "$@" + EOF + sudo chmod +x $OHOS_NDK_HOME/native/llvm/aarch64-unknown-linux-ohos-clang.sh + + - name: Build + working-directory: ./easytier-contrib/easytier-ohrs + run: | + sudo apt-get install -y llvm clang lldb lld + sudo apt-get install -y protobuf-compiler + bash ../../.github/workflows/install_rust.sh + source env.sh + cargo install ohrs + rustup target add aarch64-unknown-linux-ohos + ohrs doctor + ohrs build --release --arch aarch + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: easytier-ohos + path: ./easytier-contrib/easytier-ohrs/dist/arm64-v8a/libeasytier_ohrs.so + retention-days: 5 + if-no-files-found: error diff --git a/.gitignore b/.gitignore index 642e9a7..822a8d7 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ node_modules .vite easytier-gui/src-tauri/*.dll +/easytier-contrib/easytier-ohrs/dist/ diff --git a/Cargo.lock b/Cargo.lock index 4f6e0c1..29193e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1321,6 +1321,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.18.1" @@ -1788,7 +1797,7 @@ version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", @@ -2098,6 +2107,23 @@ dependencies = [ "uuid", ] +[[package]] +name = "easytier-ohrs" +version = "0.1.0" +dependencies = [ + "easytier", + "napi-build-ohos", + "napi-derive-ohos", + "napi-ohos", + "ohos-hilog-binding", + "once_cell", + "serde_json", + "tracing", + "tracing-core", + "tracing-subscriber", + "uuid", +] + [[package]] name = "easytier-rpc-build" version = "0.1.0" @@ -4510,6 +4536,67 @@ dependencies = [ "typenum", ] +[[package]] +name = "napi-build-ohos" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ad5bf214216afe5b572da0bcd5cab932d17cbcca3dbe82991db0d765a764c8a" + +[[package]] +name = "napi-derive-backend-ohos" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd974d6316c670078fa15276c6134e5b45142b393db350b24682ae613733cdac" +dependencies = [ + "convert_case 0.7.1", + "once_cell", + "proc-macro2", + "quote", + "semver", + "syn 2.0.87", +] + +[[package]] +name = "napi-derive-ohos" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3a8b89bbc39f81c472e76813dcd837f311aae7850a24a01d0bf5858221b1fd2" +dependencies = [ + "convert_case 0.7.1", + "napi-derive-backend-ohos", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "napi-ohos" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32036ede4ef064610304337831e9d49dac23e7edc4e9efd076c8259eab6d19a9" +dependencies = [ + "bitflags 2.8.0", + "chrono", + "ctor", + "encoding_rs", + "futures-core", + "indexmap 2.7.1", + "napi-sys-ohos", + "serde", + "serde_json", + "tokio", + "tokio-stream", +] + +[[package]] +name = "napi-sys-ohos" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e18642400316f886a6f153b2fbc48f5652d0e117803057005f89f0e48217d64" +dependencies = [ + "libloading 0.8.5", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -5128,6 +5215,22 @@ dependencies = [ "memchr", ] +[[package]] +name = "ohos-hilog-binding" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f360d22e965a34286283d36e8864fdfb04f443697641e8f6cbd64e670c3a3d5" +dependencies = [ + "libc", + "ohos-hilogs-sys", +] + +[[package]] +name = "ohos-hilogs-sys" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed07615005d0f8d7bcf901f89c8ff4870666a9bdb00382f588af383f40c160b7" + [[package]] name = "once_cell" version = "1.21.3" @@ -9062,8 +9165,7 @@ checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" [[package]] name = "tun-easytier" version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10dff0358b37ef593a74c9d2264a1df126e169d194878732a4f99ff7b01678bd" +source = "git+https://github.com/EasyTier/rust-tun#12378839e7985283df0e4fb536b7137230356db5" dependencies = [ "bytes", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 40a0833..3524626 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "easytier-rpc-build", "easytier-web", "easytier-contrib/easytier-ffi", + "easytier-contrib/easytier-ohrs", ] default-members = ["easytier", "easytier-web"] diff --git a/easytier-contrib/easytier-ffi/src/lib.rs b/easytier-contrib/easytier-ffi/src/lib.rs index 4e2f66c..da7fcc9 100644 --- a/easytier-contrib/easytier-ffi/src/lib.rs +++ b/easytier-contrib/easytier-ffi/src/lib.rs @@ -29,6 +29,30 @@ fn set_error_msg(msg: &str) { msg_buf[..len].copy_from_slice(bytes); } +#[no_mangle] +pub extern "C" fn set_tun_fd( + inst_name: *const std::ffi::c_char, + fd: std::ffi::c_int, +) -> std::ffi::c_int { + let inst_name = unsafe { + assert!(!inst_name.is_null()); + std::ffi::CStr::from_ptr(inst_name) + .to_string_lossy() + .into_owned() + }; + if !INSTANCE_NAME_ID_MAP.contains_key(&inst_name) { + return -1; + } + match INSTANCE_MANAGER.set_tun_fd(&INSTANCE_NAME_ID_MAP.get(&inst_name).unwrap().value(), fd) { + Ok(_) => { + 0 + } + Err(_) => { + -1 + } + } +} + #[no_mangle] pub extern "C" fn get_error_msg(out: *mut *const std::ffi::c_char) { let msg_buf = ERROR_MSG.lock().unwrap(); diff --git a/easytier-contrib/easytier-ohrs/Cargo.toml b/easytier-contrib/easytier-ohrs/Cargo.toml new file mode 100644 index 0000000..3fdb19e --- /dev/null +++ b/easytier-contrib/easytier-ohrs/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "easytier-ohrs" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type=["cdylib"] + +[dependencies] +ohos-hilog-binding = {version = "*", features = ["redirect"]} +easytier = { path = "../../easytier" } +napi-derive-ohos = "1.0.4" +napi-ohos = { version = "1.0.4", default-features = false, features = [ + "serde-json", + "latin1", + "chrono_date", + "object_indexmap", + "tokio", + "async", + "tokio_rt", + "tokio_macros", + "tokio_io_util", + "deferred_trace", + "napi8", + "node_version_detect", + "web_stream", +] } +once_cell = "1.21.3" +serde_json = "1.0.125" +tracing-subscriber = "0.3.19" +tracing-core = "0.1.33" +tracing = "0.1.41" +uuid = { version = "1.17.0", features = ["v4"] } + +[build-dependencies] +napi-build-ohos = "1.0.4" +[profile.dev] +panic = "unwind" +debug = true + +[profile.release] +panic = "abort" +lto = true +codegen-units = 1 +opt-level = 3 +strip = true diff --git a/easytier-contrib/easytier-ohrs/README.md b/easytier-contrib/easytier-ohrs/README.md new file mode 100644 index 0000000..caeddc5 --- /dev/null +++ b/easytier-contrib/easytier-ohrs/README.md @@ -0,0 +1,65 @@ +# OpenHarmonyOS 项目构建说明 + +本项目需要 OpenHarmonyOS SDK 和多个基础库支持才能成功编译。请按照以下步骤准备构建环境。 +如存在任何编译问题,请前往[Easytier for OHOS](https://github.com/FrankHan052176/EasyTier) + +## 前置要求 + +### 1. 安装 OpenHarmonyOS SDK + +**SDK 下载链接**: +[OpenHarmony 每日构建版本](https://ci.openharmony.cn/workbench/cicd/dailybuild/dailylist) + +**版本要求**: +请选择版本号 **小于 OpenHarmony_5.1.0.58** 的 ohos-sdk-full 版本 + +下载后请解压到适当位置(如 `/usr/local/ohos-sdk`),并记下安装路径。 + +### 2. 编译依赖库 +在编译本项目前,需要先自行编译以下四个基础库: + +- glib +- libffi +- pcre2 +- zlib + +这些库需要使用 OpenHarmonyOS 的工具链进行交叉编译。 + +## 环境配置 + +### 1. 设置环境变量 +创建并运行以下脚本设置环境变量(请根据您的实际 SDK 安装路径修改): + +```bash +#!/bin/bash +# 请修改为您的实际 SDK 路径 +export OHOS_SDK_PATH="/usr/local/ohos-sdk/linux" +export OHOS_TOOLCHAIN_DIR="${OHOS_SDK_PATH}/native/llvm" +export TARGET_ARCH="aarch64-linux-ohos" +export OHOS_SYSROOT="${OHOS_SDK_PATH}/native/sysroot" +export CC="${OHOS_TOOLCHAIN_DIR}/bin/aarch64-unknown-linux-ohos-clang" +export CXX="${OHOS_TOOLCHAIN_DIR}/bin/aarch64-unknown-linux-ohos-clang++" +export AS="${OHOS_TOOLCHAIN_DIR}/bin/llvm-as" +export AR="${OHOS_TOOLCHAIN_DIR}/bin/llvm-ar" +export LD="${OHOS_TOOLCHAIN_DIR}/bin/ld.lld" +export RANLIB="${OHOS_TOOLCHAIN_DIR}/bin/llvm-ranlib" +export STRIP="${OHOS_TOOLCHAIN_DIR}/bin/llvm-strip" +export OBJDUMP="${OHOS_TOOLCHAIN_DIR}/bin/llvm-objdump" +export OBJCOPY="${OHOS_TOOLCHAIN_DIR}/bin/llvm-objcopy" +export NM="${OHOS_TOOLCHAIN_DIR}/bin/llvm-nm" +export CFLAGS="-fPIC -D__MUSL__=1 -march=armv8-a --target=${TARGET_ARCH} -Wno-error --sysroot=${OHOS_SYSROOT} -I${OHOS_SYSROOT}/usr/include/${TARGET_ARCH}" +export CXXFLAGS="${CFLAGS}" +export LDFLAGS="--sysroot=${OHOS_SYSROOT} -L${OHOS_SYSROOT}/usr/lib/${TARGET_ARCH} -fuse-ld=${LD}" +export PKG_CONFIG_PATH="${OHOS_SYSROOT}/usr/lib/pkgconfig:${OHOS_SYSROOT}/usr/local/lib/pkgconfig" +export PKG_CONFIG_LIBDIR="${OHOS_SYSROOT}/usr/lib:${OHOS_SYSROOT}/usr/local/lib" +export PKG_CONFIG_SYSROOT_DIR="${OHOS_SYSROOT}" +export HOST_TRIPLET="${TARGET_ARCH}" +export BUILD_TRIPLET="$(dpkg-architecture -qDEB_BUILD_GNU_TYPE)" +export PATH="${OHOS_TOOLCHAIN_DIR}/bin:${PATH}" + +echo "OpenHarmonyOS 环境变量已设置:" +echo "OHOS_SDK_PATH: ${OHOS_SDK_PATH}" +echo "OHOS_TOOLCHAIN_DIR: ${OHOS_TOOLCHAIN_DIR}" +echo "OHOS_SYSROOT: ${OHOS_SYSROOT}" +echo "PKG_CONFIG_PATH: ${PKG_CONFIG_PATH}" +echo "PATH: ${PATH}" diff --git a/easytier-contrib/easytier-ohrs/build.rs b/easytier-contrib/easytier-ohrs/build.rs new file mode 100644 index 0000000..1320ceb --- /dev/null +++ b/easytier-contrib/easytier-ohrs/build.rs @@ -0,0 +1,3 @@ +fn main () { + napi_build_ohos::setup(); +} \ No newline at end of file diff --git a/easytier-contrib/easytier-ohrs/env.sh b/easytier-contrib/easytier-ohrs/env.sh new file mode 100644 index 0000000..1736daa --- /dev/null +++ b/easytier-contrib/easytier-ohrs/env.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# 请修改为您的实际 SDK 路径 +export OHOS_TOOLCHAIN_DIR="${OHOS_NDK_HOME}/native/llvm" +export TARGET_ARCH="aarch64-linux-ohos" +export OHOS_SYSROOT="${OHOS_NDK_HOME}/native/sysroot" +export CC="${OHOS_TOOLCHAIN_DIR}/bin/aarch64-unknown-linux-ohos-clang" +export CXX="${OHOS_TOOLCHAIN_DIR}/bin/aarch64-unknown-linux-ohos-clang++" +export AS="${OHOS_TOOLCHAIN_DIR}/bin/llvm-as" +export AR="${OHOS_TOOLCHAIN_DIR}/bin/llvm-ar" +export LD="${OHOS_TOOLCHAIN_DIR}/bin/ld.lld" +export RANLIB="${OHOS_TOOLCHAIN_DIR}/bin/llvm-ranlib" +export STRIP="${OHOS_TOOLCHAIN_DIR}/bin/llvm-strip" +export OBJDUMP="${OHOS_TOOLCHAIN_DIR}/bin/llvm-objdump" +export OBJCOPY="${OHOS_TOOLCHAIN_DIR}/bin/llvm-objcopy" +export NM="${OHOS_TOOLCHAIN_DIR}/bin/llvm-nm" +export CFLAGS="-fPIC -D__MUSL__=1 -march=armv8-a --target=${TARGET_ARCH} -Wno-error --sysroot=${OHOS_SYSROOT} -I${OHOS_SYSROOT}/usr/include/${TARGET_ARCH}" +export CXXFLAGS="${CFLAGS}" +export LDFLAGS="--sysroot=${OHOS_SYSROOT} -L${OHOS_SYSROOT}/usr/lib/${TARGET_ARCH} -fuse-ld=${LD}" +export PKG_CONFIG_PATH="${OHOS_SYSROOT}/usr/lib/pkgconfig:${OHOS_SYSROOT}/usr/local/lib/pkgconfig" +export PKG_CONFIG_LIBDIR="${OHOS_SYSROOT}/usr/lib:${OHOS_SYSROOT}/usr/local/lib" +export PKG_CONFIG_SYSROOT_DIR="${OHOS_SYSROOT}" +export HOST_TRIPLET="${TARGET_ARCH}" +export BUILD_TRIPLET="$(dpkg-architecture -qDEB_BUILD_GNU_TYPE)" +export PATH="${OHOS_TOOLCHAIN_DIR}/bin:${PATH}" + +echo "OpenHarmonyOS 环境变量已设置:" +echo "OHOS_SDK_PATH: ${OHOS_NDK_HOME}" +echo "OHOS_TOOLCHAIN_DIR: ${OHOS_TOOLCHAIN_DIR}" +echo "OHOS_SYSROOT: ${OHOS_SYSROOT}" +echo "PKG_CONFIG_PATH: ${PKG_CONFIG_PATH}" +echo "PATH: ${PATH}" diff --git a/easytier-contrib/easytier-ohrs/src/lib.rs b/easytier-contrib/easytier-ohrs/src/lib.rs new file mode 100644 index 0000000..e1e7518 --- /dev/null +++ b/easytier-contrib/easytier-ohrs/src/lib.rs @@ -0,0 +1,148 @@ +mod native_log; + +use easytier::common::config::{ConfigLoader, TomlConfigLoader}; +use easytier::instance_manager::NetworkInstanceManager; +use easytier::launcher::ConfigSource; +use napi_derive_ohos::napi; +use ohos_hilog_binding::{hilog_debug, hilog_error}; +use std::format; +use uuid::Uuid; + +static INSTANCE_MANAGER: once_cell::sync::Lazy = + once_cell::sync::Lazy::new(NetworkInstanceManager::new); + +#[napi(object)] +pub struct KeyValuePair { + pub key: String, + pub value: String, +} + +#[napi] +pub fn set_tun_fd( + inst_id: String, + fd: i32, +) -> bool { + match Uuid::try_parse(&inst_id) { + Ok(uuid) => { + match INSTANCE_MANAGER.set_tun_fd(&uuid, fd) { + Ok(_) => { + hilog_debug!("[Rust] set tun fd {} to {}.", fd, inst_id); + true + } + Err(e) => { + hilog_error!("[Rust] cant set tun fd {} to {}. {}", fd, inst_id, e); + false + } + } + } + Err(e) => { + hilog_error!("[Rust] cant covert {} to uuid. {}", inst_id, e); + false + } + } +} + +#[napi] +pub fn parse_config(cfg_str: String) -> bool { + match TomlConfigLoader::new_from_str(&cfg_str) { + Ok(_) => { + true + } + Err(e) => { + hilog_error!("[Rust] parse config failed {}", e); + false + } + } +} + +#[napi] +pub fn run_network_instance(cfg_str: String) -> bool { + let cfg = match TomlConfigLoader::new_from_str(&cfg_str) { + Ok(cfg) => cfg, + Err(e) => { + hilog_error!("[Rust] parse config failed {}", e); + return false; + } + }; + + if INSTANCE_MANAGER.list_network_instance_ids().len() > 0 { + hilog_error!("[Rust] there is a running instance!"); + return false; + } + + let inst_id = cfg.get_id(); + if INSTANCE_MANAGER + .list_network_instance_ids() + .contains(&inst_id) + { + return false; + } + INSTANCE_MANAGER + .run_network_instance(cfg, ConfigSource::FFI) + .unwrap(); + true +} + +#[napi] +pub fn stop_network_instance(inst_names: Vec) { + INSTANCE_MANAGER + .delete_network_instance( + inst_names + .into_iter() + .filter_map(|s| Uuid::parse_str(&s).ok()) + .collect(), + ) + .unwrap(); + hilog_debug!("[Rust] stop_network_instance"); +} + +#[napi] +pub fn collect_network_infos() -> Vec { + let mut result = Vec::new(); + match INSTANCE_MANAGER.collect_network_infos() { + Ok(map) => { + for (uuid, info) in map.iter() { + // convert value to json string + let value = match serde_json::to_string(&info) { + Ok(value) => value, + Err(e) => { + hilog_error!("[Rust] failed to serialize instance {} info: {}", uuid, e); + continue; + } + }; + result.push(KeyValuePair { + key: uuid.clone().to_string(), + value: value.clone(), + }); + } + } + Err(_) => {} + } + result +} + +#[napi] +pub fn collect_running_network() -> Vec { + INSTANCE_MANAGER + .list_network_instance_ids() + .clone() + .into_iter() + .map(|id| id.to_string()) + .collect() +} + +#[napi] +pub fn is_running_network(inst_id: String) -> bool { + match Uuid::try_parse(&inst_id) { + Ok(uuid) => { + INSTANCE_MANAGER + .list_network_instance_ids() + .contains(&uuid) + } + Err(e) => { + hilog_error!("[Rust] cant covert {} to uuid. {}", inst_id, e); + false + } + } + +} diff --git a/easytier-contrib/easytier-ohrs/src/native_log.rs b/easytier-contrib/easytier-ohrs/src/native_log.rs new file mode 100644 index 0000000..221dce1 --- /dev/null +++ b/easytier-contrib/easytier-ohrs/src/native_log.rs @@ -0,0 +1,98 @@ +use std::collections::HashMap; +use std::panic; +use napi_derive_ohos::napi; +use ohos_hilog_binding::{hilog_debug, hilog_error, hilog_info, hilog_warn, set_global_options, LogOptions}; +use tracing::{Event, Subscriber}; +use tracing_core::Level; +use tracing_subscriber::layer::{Context, Layer}; +use tracing_subscriber::prelude::*; + +static INITIALIZED: std::sync::Once = std::sync::Once::new(); +fn panic_hook(info: &panic::PanicHookInfo) { + hilog_error!("RUST PANIC: {}", info); +} + +#[napi] +pub fn init_panic_hook() { + INITIALIZED.call_once(|| { + panic::set_hook(Box::new(panic_hook)); + }); +} + +#[napi] +pub fn hilog_global_options( + domain: u32, + tag: String, +) { + ohos_hilog_binding::forward_stdio_to_hilog(); + set_global_options(LogOptions{ + domain, + tag: Box::leak(tag.clone().into_boxed_str()), + }) +} + +#[napi] +pub fn init_tracing_subscriber() { + tracing_subscriber::registry() + .with( + CallbackLayer { + callback: Box::new(tracing_callback), + } + ) + .init(); +} + +fn tracing_callback(event: &Event, fields: HashMap) { + let metadata = event.metadata(); + #[cfg(target_env = "ohos")] + { + let loc = metadata.target().split("::").last().unwrap(); + match *metadata.level() { + Level::TRACE => { + hilog_debug!("[{}] {:?}", loc, fields.values().collect::>()); + } + Level::DEBUG => { + hilog_debug!("[{}] {:?}", loc, fields.values().collect::>()); + } + Level::INFO => { + hilog_info!("[{}] {:?}", loc, fields.values().collect::>()); + } + Level::WARN => { + hilog_warn!("[{}] {:?}", loc, fields.values().collect::>()); + } + Level::ERROR => { + hilog_error!("[{}] {:?}", loc, fields.values().collect::>()); + } + } + } +} + +struct CallbackLayer { + callback: Box) + Send + Sync>, +} + +impl Layer for CallbackLayer { + fn on_event(&self, event: &Event, _ctx: Context) { + // 使用 fmt::format::FmtSpan 提取字段值 + let mut fields = HashMap::new(); + let mut visitor = FieldCollector(&mut fields); + event.record(&mut visitor); + (self.callback)(event, fields); + } +} + +struct FieldCollector<'a>(&'a mut HashMap); + +impl<'a> tracing::field::Visit for FieldCollector<'a> { + fn record_i64(&mut self, field: &tracing::field::Field, value: i64) { + self.0.insert(field.name().to_string(), value.to_string()); + } + + fn record_str(&mut self, field: &tracing::field::Field, value: &str) { + self.0.insert(field.name().to_string(), value.to_string()); + } + + fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) { + self.0.insert(field.name().to_string(), format!("{:?}", value)); + } +} \ No newline at end of file diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index f1acd17..dfbc817 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -85,7 +85,7 @@ http = { version = "1", default-features = false, features = [ tokio-rustls = { version = "0.26", default-features = false, optional = true } # for tap device -tun = { package = "tun-easytier", version = "1.1.1", features = [ +tun = { package = "tun-easytier", git="https://github.com/EasyTier/rust-tun", features = [ "async", ], optional = true } # for net ns diff --git a/easytier/src/common/global_ctx.rs b/easytier/src/common/global_ctx.rs index 59df861..803df87 100644 --- a/easytier/src/common/global_ctx.rs +++ b/easytier/src/common/global_ctx.rs @@ -107,7 +107,7 @@ impl GlobalCtx { let stun_info_collection = Arc::new(StunInfoCollector::new_with_default_servers()); - let enable_exit_node = config_fs.get_flags().enable_exit_node; + let enable_exit_node = config_fs.get_flags().enable_exit_node || cfg!(target_env= "ohos"); let proxy_forward_by_system = config_fs.get_flags().proxy_forward_by_system; let no_tun = config_fs.get_flags().no_tun; diff --git a/easytier/src/common/network.rs b/easytier/src/common/network.rs index 8396a30..e4d72f6 100644 --- a/easytier/src/common/network.rs +++ b/easytier/src/common/network.rs @@ -16,14 +16,14 @@ struct InterfaceFilter { iface: NetworkInterface, } -#[cfg(target_os = "android")] +#[cfg(any(target_os = "android", target_env = "ohos"))] impl InterfaceFilter { async fn filter_iface(&self) -> bool { true } } -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] impl InterfaceFilter { async fn is_tun_tap_device(&self) -> bool { let path = format!("/sys/class/net/{}/tun_flags", self.iface.name); diff --git a/easytier/src/connector/mod.rs b/easytier/src/connector/mod.rs index 746765c..ba202cd 100644 --- a/easytier/src/connector/mod.rs +++ b/easytier/src/connector/mod.rs @@ -29,7 +29,7 @@ async fn set_bind_addr_for_peer_connector( is_ipv4: bool, ip_collector: &Arc, ) { - if cfg!(target_os = "android") { + if cfg!(any(target_os = "android", target_env = "ohos")) { return; } diff --git a/easytier/src/gateway/tcp_proxy.rs b/easytier/src/gateway/tcp_proxy.rs index def3b73..6884c5e 100644 --- a/easytier/src/gateway/tcp_proxy.rs +++ b/easytier/src/gateway/tcp_proxy.rs @@ -520,7 +520,7 @@ impl TcpProxy { #[cfg(feature = "smoltcp")] if self.global_ctx.get_flags().use_smoltcp || self.global_ctx.no_tun() - || cfg!(target_os = "android") + || cfg!(any(target_os = "android", target_env = "ohos")) { // use smoltcp network stack self.local_port diff --git a/easytier/src/instance/instance.rs b/easytier/src/instance/instance.rs index 7360e0e..2936773 100644 --- a/easytier/src/instance/instance.rs +++ b/easytier/src/instance/instance.rs @@ -89,8 +89,8 @@ impl IpProxy { self.tcp_proxy.start(true).await?; if let Err(e) = self.icmp_proxy.start().await { tracing::error!("start icmp proxy failed: {:?}", e); - if cfg!(not(target_os = "android")) { - // android may not support icmp proxy + if cfg!(not(any(target_os = "android", target_env = "ohos"))) { + // android and ohos not support icmp proxy return Err(e); } } @@ -477,7 +477,7 @@ impl Instance { continue; } - #[cfg(not(target_os = "android"))] + #[cfg(not(any(target_os = "android", target_env = "ohos")))] { let mut new_nic_ctx = NicCtx::new( global_ctx_c.clone(), @@ -531,7 +531,7 @@ impl Instance { Self::clear_nic_ctx(self.nic_ctx.clone(), self.peer_packet_receiver.clone()).await; if !self.global_ctx.config.get_flags().no_tun { - #[cfg(not(target_os = "android"))] + #[cfg(not(any(target_os = "android", target_env = "ohos")))] if let Some(ipv4_addr) = self.global_ctx.get_ipv4() { let mut new_nic_ctx = NicCtx::new( self.global_ctx.clone(), @@ -796,7 +796,7 @@ impl Instance { self.peer_packet_receiver.clone() } - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] pub async fn setup_nic_ctx_for_android( nic_ctx: ArcNicCtx, global_ctx: ArcGlobalCtx, diff --git a/easytier/src/instance/virtual_nic.rs b/easytier/src/instance/virtual_nic.rs index 8ee2dcf..6330a15 100644 --- a/easytier/src/instance/virtual_nic.rs +++ b/easytier/src/instance/virtual_nic.rs @@ -110,7 +110,7 @@ enum PacketProtocol { // Note: the protocol in the packet information header is platform dependent. impl PacketProtocol { - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_env = "ohos"))] fn into_pi_field(self) -> Result { use nix::libc; match self { @@ -328,7 +328,7 @@ impl VirtualNic { Ok(tun::create(&config)?) } - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] pub async fn create_dev_for_android( &mut self, tun_fd: std::os::fd::RawFd, @@ -690,7 +690,7 @@ impl NicCtx { Ok(()) } - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] pub async fn run_for_android(&mut self, tun_fd: std::os::fd::RawFd) -> Result<(), Error> { let tunnel = { let mut nic = self.nic.lock().await; diff --git a/easytier/src/launcher.rs b/easytier/src/launcher.rs index cdfe7ec..eb21cc7 100644 --- a/easytier/src/launcher.rs +++ b/easytier/src/launcher.rs @@ -94,7 +94,7 @@ impl EasyTierLauncher { } } - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] async fn run_routine_for_android( instance: &Instance, data: &EasyTierData, @@ -199,7 +199,7 @@ impl EasyTierLauncher { }); } - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] Self::run_routine_for_android(&instance, &data, &mut tasks).await; instance.run().await?; diff --git a/easytier/src/peers/peer_manager.rs b/easytier/src/peers/peer_manager.rs index f93b082..de0c31c 100644 --- a/easytier/src/peers/peer_manager.rs +++ b/easytier/src/peers/peer_manager.rs @@ -862,7 +862,14 @@ impl PeerManager { } } } - + #[cfg(target_env = "ohos")] + { + if dst_peers.is_empty() { + tracing::info!("no peer id for ipv4: {}, set exit_node for ohos", ipv4_addr); + dst_peers.push(self.my_peer_id.clone()); + is_exit_node = true; + } + } (dst_peers, is_exit_node) } diff --git a/easytier/src/tunnel/common.rs b/easytier/src/tunnel/common.rs index 3a08031..34e230f 100644 --- a/easytier/src/tunnel/common.rs +++ b/easytier/src/tunnel/common.rs @@ -388,7 +388,7 @@ pub(crate) fn setup_sokcet2_ext( } } - #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux", target_env = "ohos"))] if let Some(dev_name) = bind_dev { tracing::trace!(dev_name = ?dev_name, "bind device"); socket2_socket.bind_device(Some(dev_name.as_bytes()))?;