From f12ae3b8f7e08c021276340e24f5082053f645ad Mon Sep 17 00:00:00 2001 From: richerfu <southorange0929@foxmail.com> Date: Tue, 19 Nov 2024 16:35:47 +0800 Subject: [PATCH] feat: support openharmony platform --- README.md | 1 + examples/dev-config.rs | 2 +- examples/ping-tun.rs | 2 +- examples/read-async-codec.rs | 2 +- examples/read-async.rs | 2 +- examples/read.rs | 2 +- examples/split.rs | 2 +- examples/write.rs | 2 +- src/platform/mod.rs | 9 +- src/platform/ohos/device.rs | 174 +++++++++++++++++++++++++++++++++++ src/platform/ohos/mod.rs | 30 ++++++ 11 files changed, 219 insertions(+), 9 deletions(-) create mode 100644 src/platform/ohos/device.rs create mode 100644 src/platform/ohos/mod.rs diff --git a/README.md b/README.md index 2a9de1be..b6dc7dc1 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Platforms - [x] FreeBSD - [x] Android - [x] iOS +- [x] OpenHarmony Linux diff --git a/examples/dev-config.rs b/examples/dev-config.rs index bd9fa153..f36c3c1c 100644 --- a/examples/dev-config.rs +++ b/examples/dev-config.rs @@ -41,7 +41,7 @@ fn main_entry(quit: Receiver<()>) -> Result<(), BoxError> { .destination((10, 0, 0, 1)) .up(); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] config.platform_config(|config| { config.ensure_root_privileges(true); }); diff --git a/examples/ping-tun.rs b/examples/ping-tun.rs index 2e13ef57..bdf54e32 100644 --- a/examples/ping-tun.rs +++ b/examples/ping-tun.rs @@ -40,7 +40,7 @@ async fn main_entry(mut quit: Receiver<()>) -> Result<(), BoxError> { .destination((10, 0, 0, 1)) .up(); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] config.platform_config(|config| { #[allow(deprecated)] config.packet_information(true); diff --git a/examples/read-async-codec.rs b/examples/read-async-codec.rs index a0d16d10..976dd867 100644 --- a/examples/read-async-codec.rs +++ b/examples/read-async-codec.rs @@ -64,7 +64,7 @@ async fn main_entry(mut quit: Receiver<()>) -> Result<(), BoxError> { .destination((10, 0, 0, 1)) .up(); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] config.platform_config(|config| { #[allow(deprecated)] config.packet_information(true); diff --git a/examples/read-async.rs b/examples/read-async.rs index 62d52bf6..c5dcc5e1 100644 --- a/examples/read-async.rs +++ b/examples/read-async.rs @@ -40,7 +40,7 @@ async fn main_entry(mut quit: Receiver<()>) -> Result<(), BoxError> { .mtu(tun::DEFAULT_MTU) .up(); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] config.platform_config(|config| { config.ensure_root_privileges(true); }); diff --git a/examples/read.rs b/examples/read.rs index 377f2ecd..97f5de12 100644 --- a/examples/read.rs +++ b/examples/read.rs @@ -40,7 +40,7 @@ fn main_entry(quit: Receiver<()>) -> Result<(), BoxError> { .destination((10, 0, 0, 1)) .up(); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] config.platform_config(|config| { config.ensure_root_privileges(true); }); diff --git a/examples/split.rs b/examples/split.rs index 07774ff5..f32d69ba 100644 --- a/examples/split.rs +++ b/examples/split.rs @@ -41,7 +41,7 @@ fn main_entry(quit: Receiver<()>) -> Result<(), BoxError> { .destination((10, 0, 0, 1)) .up(); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] config.platform_config(|config| { config.ensure_root_privileges(true); }); diff --git a/examples/write.rs b/examples/write.rs index ed4245a6..3d619713 100644 --- a/examples/write.rs +++ b/examples/write.rs @@ -41,7 +41,7 @@ fn main_entry(quit: Receiver<()>) -> Result<(), BoxError> { .destination((10, 0, 0, 1)) .up(); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] config.platform_config(|config| { config.ensure_root_privileges(true); }); diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 9973d928..a699a72a 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -17,9 +17,9 @@ #[cfg(unix)] pub(crate) mod posix; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] pub(crate) mod linux; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] pub use self::linux::{create, Device, PlatformConfig}; #[cfg(target_os = "freebsd")] @@ -42,6 +42,11 @@ pub(crate) mod android; #[cfg(target_os = "android")] pub use self::android::{create, Device, PlatformConfig}; +#[cfg(target_env = "ohos")] +pub(crate) mod ohos; +#[cfg(target_env = "ohos")] +pub use self::ohos::{create, Device, PlatformConfig}; + #[cfg(unix)] pub use crate::platform::posix::Tun; diff --git a/src/platform/ohos/device.rs b/src/platform/ohos/device.rs new file mode 100644 index 00000000..3e703eed --- /dev/null +++ b/src/platform/ohos/device.rs @@ -0,0 +1,174 @@ +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// Version 2, December 2004 +// +// Copyleft (ↄ) meh. <meh@schizofreni.co> | http://meh.schizofreni.co +// +// Everyone is permitted to copy and distribute verbatim or modified +// copies of this license document, and changing it is allowed as long +// as the name is changed. +// +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +// +// 0. You just DO WHAT THE FUCK YOU WANT TO. +#![allow(unused_variables)] + +use std::io::{Read, Write}; +use std::net::IpAddr; +use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; + +use crate::configuration::Configuration; +use crate::device::AbstractDevice; +use crate::error::{Error, Result}; +use crate::platform::posix::{self, Fd, Tun}; + +/// A TUN device for Android. +pub struct Device { + tun: Tun, +} + +impl AsRef<dyn AbstractDevice + 'static> for Device { + fn as_ref(&self) -> &(dyn AbstractDevice + 'static) { + self + } +} + +impl AsMut<dyn AbstractDevice + 'static> for Device { + fn as_mut(&mut self) -> &mut (dyn AbstractDevice + 'static) { + self + } +} + +impl Device { + /// Create a new `Device` for the given `Configuration`. + pub fn new(config: &Configuration) -> Result<Self> { + let close_fd_on_drop = config.close_fd_on_drop.unwrap_or(true); + let fd = match config.raw_fd { + Some(raw_fd) => raw_fd, + _ => return Err(Error::InvalidConfig), + }; + let device = { + let mtu = config.mtu.unwrap_or(crate::DEFAULT_MTU); + let tun = Fd::new(fd, close_fd_on_drop).map_err(|_| std::io::Error::last_os_error())?; + + Device { + tun: Tun::new(tun, mtu, false), + } + }; + + Ok(device) + } + + /// Split the interface into a `Reader` and `Writer`. + pub fn split(self) -> (posix::Reader, posix::Writer) { + (self.tun.reader, self.tun.writer) + } + + /// Set non-blocking mode + pub fn set_nonblock(&self) -> std::io::Result<()> { + self.tun.set_nonblock() + } + + /// Recv a packet from tun device + pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> { + self.tun.recv(buf) + } + + /// Send a packet to tun device + pub fn send(&self, buf: &[u8]) -> std::io::Result<usize> { + self.tun.send(buf) + } +} + +impl Read for Device { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { + self.tun.read(buf) + } +} + +impl Write for Device { + fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { + self.tun.write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.tun.flush() + } +} + +impl AbstractDevice for Device { + fn tun_index(&self) -> Result<i32> { + Err(Error::NotImplemented) + } + + fn tun_name(&self) -> Result<String> { + Ok("".to_string()) + } + + fn set_tun_name(&mut self, value: &str) -> Result<()> { + Err(Error::NotImplemented) + } + + fn enabled(&mut self, value: bool) -> Result<()> { + Ok(()) + } + + fn address(&self) -> Result<IpAddr> { + Err(Error::NotImplemented) + } + + fn set_address(&mut self, _value: IpAddr) -> Result<()> { + Ok(()) + } + + fn destination(&self) -> Result<IpAddr> { + Err(Error::NotImplemented) + } + + fn set_destination(&mut self, _value: IpAddr) -> Result<()> { + Ok(()) + } + + fn broadcast(&self) -> Result<IpAddr> { + Err(Error::NotImplemented) + } + + fn set_broadcast(&mut self, _value: IpAddr) -> Result<()> { + Ok(()) + } + + fn netmask(&self) -> Result<IpAddr> { + Err(Error::NotImplemented) + } + + fn set_netmask(&mut self, _value: IpAddr) -> Result<()> { + Ok(()) + } + + fn mtu(&self) -> Result<u16> { + // TODO: must get the mtu from the underlying device driver + Ok(self.tun.mtu()) + } + + fn set_mtu(&mut self, value: u16) -> Result<()> { + // TODO: must set the mtu to the underlying device driver + self.tun.set_mtu(value); + Ok(()) + } + + fn packet_information(&self) -> bool { + self.tun.packet_information() + } +} + +impl AsRawFd for Device { + fn as_raw_fd(&self) -> RawFd { + self.tun.as_raw_fd() + } +} + +impl IntoRawFd for Device { + fn into_raw_fd(self) -> RawFd { + self.tun.into_raw_fd() + } +} diff --git a/src/platform/ohos/mod.rs b/src/platform/ohos/mod.rs new file mode 100644 index 00000000..b6ab7167 --- /dev/null +++ b/src/platform/ohos/mod.rs @@ -0,0 +1,30 @@ +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// Version 2, December 2004 +// +// Copyleft (ↄ) meh. <meh@schizofreni.co> | http://meh.schizofreni.co +// +// Everyone is permitted to copy and distribute verbatim or modified +// copies of this license document, and changing it is allowed as long +// as the name is changed. +// +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +// +// 0. You just DO WHAT THE FUCK YOU WANT TO. + +//! OpenHarmony specific functionality. + +mod device; +pub use self::device::Device; + +use crate::configuration::Configuration; +use crate::error::Result; + +/// Android-only interface configuration. +#[derive(Copy, Clone, Default, Debug)] +pub struct PlatformConfig; + +/// Create a TUN device with the given name. +pub fn create(configuration: &Configuration) -> Result<Device> { + Device::new(configuration) +}