Add thread spawning FFI

This commit is contained in:
Jett Chen 2023-08-27 10:21:55 +08:00
parent a2cbd2ad77
commit 1b69b4a8e1
7 changed files with 98 additions and 29 deletions

View file

@ -4,23 +4,15 @@ import OSLog
class PacketTunnelProvider: NEPacketTunnelProvider { class PacketTunnelProvider: NEPacketTunnelProvider {
let logger = Logger(subsystem: "com.hackclub.burrow", category: "General") let logger = Logger(subsystem: "com.hackclub.burrow", category: "General")
var osInitialized = false
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
if(!osInitialized){
libburrow.initialize_oslog() libburrow.initialize_oslog()
let fild = libburrow.retrieve() osInitialized=true
if fild == -1 {
// Not sure if this is the right way to return an error
logger.error("Failed to retrieve file descriptor for burrow.")
let err = NSError(
domain: "com.hackclub.burrow",
code: 1_010,
userInfo: [NSLocalizedDescriptionKey: "Failed to find TunInterface"]
)
completionHandler(err)
} }
logger.info("fd: \(fild)") libburrow.spawn_server()
let network_settings = genNetSec(fild: fild) logger.debug("spawned server")
logger.info("Network Settings: - ipv4:\(network_settings.ipv4Settings) -mtu: \(network_settings.mtu)")
completionHandler(nil) completionHandler(nil)
} }

View file

@ -9,3 +9,4 @@ typedef struct {
NetWorkSettings getNetworkSettings(int); NetWorkSettings getNetworkSettings(int);
void initialize_oslog(); void initialize_oslog();
void spawn_server();

11
Cargo.lock generated
View file

@ -1136,6 +1136,16 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi 0.3.1",
"libc",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.17.1" version = "1.17.1"
@ -1768,6 +1778,7 @@ dependencies = [
"bytes", "bytes",
"libc", "libc",
"mio", "mio",
"num_cpus",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio-macros", "tokio-macros",

View file

@ -7,7 +7,7 @@ edition = "2021"
crate-type = ["lib", "staticlib"] crate-type = ["lib", "staticlib"]
[dependencies] [dependencies]
tokio = { version = "1.21", features = ["rt", "macros"] } tokio = { version = "1.21", features = ["rt", "rt-multi-thread", "macros"] }
tun = { version = "0.1", path = "../tun" , features = ["tokio"]} tun = { version = "0.1", path = "../tun" , features = ["tokio"]}
clap = { version = "4.3.2", features = ["derive"] } clap = { version = "4.3.2", features = ["derive"] }
env_logger = "0.10" env_logger = "0.10"

View file

@ -16,6 +16,8 @@ use tun::TunInterface;
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
pub use apple::{NetWorkSettings, getNetworkSettings, initialize_oslog}; pub use apple::{NetWorkSettings, getNetworkSettings, initialize_oslog};
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
pub use server::spawn_server;
// TODO Separate start and retrieve functions // TODO Separate start and retrieve functions
#[cfg(any(target_os = "linux", target_vendor = "apple"))] #[cfg(any(target_os = "linux", target_vendor = "apple"))]
@ -48,3 +50,22 @@ pub extern "C" fn retrieve() -> i32 {
} }
} }
} }
pub fn get_iface() -> Option<TunInterface> {
(1..100)
.filter_map(|i| {
debug!("Getting TunInterface with fd: {:?}", i);
let iface = unsafe { TunInterface::from_raw_fd(i) };
match iface.name() {
Ok(name) => {
debug!("Found interface {}", name);
Some(iface)
},
Err(_) => {
mem::forget(iface);
None
}
}
})
.next()
}

View file

@ -2,25 +2,72 @@ use axum::{body::Bytes, error_handling::HandleErrorLayer, extract::{DefaultBodyL
use std::{ use std::{
borrow::Cow, borrow::Cow,
collections::HashMap, collections::HashMap,
sync::{Arc, RwLock}, sync::Arc,
time::Duration, time::Duration,
}; };
use tokio::sync::RwLock;
use tokio::runtime::Runtime;
use std::net::{Ipv4Addr, SocketAddr}; use std::net::{Ipv4Addr, SocketAddr};
use axum::handler::HandlerWithoutStateExt; use axum::handler::HandlerWithoutStateExt;
use serde_json::json; use serde_json::json;
use tun::TunInterface; // TODO: refactor to tokio TunInterface, which doesn't implement `Send` use tun::tokio::TunInterface; // TODO: refactor to tokio TunInterface, which doesn't implement `Send`
use std::thread;
use crate::get_iface;
use tracing::{info, debug, error};
type SharedState = Arc<RwLock<TunInterface>>; type SharedState = Arc<RwLock<TunInterface>>;
pub async fn serve(ti: TunInterface){ #[no_mangle]
let state = Arc::new(RwLock::new( pub extern "C" fn spawn_server(){
ti info!("Spawning server");
)); let ti = get_iface().unwrap();
debug!("Got interface");
let rt = Runtime::new().unwrap();
let _handle = thread::spawn(move || {
rt.spawn(async {
service(ti).await;
});
});
debug!("Spawned thread: finish spawn server");
}
async fn service(ti: crate::TunInterface){
info!("Spawning service");
let shared_state = Arc::new(RwLock::new(TunInterface::new(ti).unwrap()));
info!("Created shared state");
let state_cl= shared_state.clone();
let lp = tokio::spawn(
async move {
burrow_loop(state_cl).await;
}
);
let srv = tokio::spawn(
async move {
serve(shared_state).await;
}
);
info!("Created threads");
tokio::join!(lp, srv);
}
async fn burrow_loop(state: SharedState){
debug!("loop called");
let mut buf = [0u8; 1504];
loop {
let n = state.write().await.read(&mut buf[..]).await.unwrap();
// do something with the data
info!("read {} bytes", n);
}
}
async fn serve(state: SharedState){
debug!("serve called");
let app_router = Router::new() let app_router = Router::new()
.route("/info", get(network_settings)) .route("/info", get(network_settings))
.with_state(state); .with_state(state);
let port = std::env::var("BURROW_PORT").unwrap_or("3000".to_string()); let port = std::env::var("BURROW_PORT").unwrap_or("3000".to_string());
let sock_addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), port.parse().unwrap()); let sock_addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), port.parse().unwrap());
info!("Listening on {}...", sock_addr);
axum::Server::bind(&sock_addr) axum::Server::bind(&sock_addr)
.serve(app_router.into_make_service()) .serve(app_router.into_make_service())
.await .await
@ -28,11 +75,11 @@ pub async fn serve(ti: TunInterface){
} }
#[debug_handler] #[debug_handler]
async fn network_settings(State(state): State<SharedState>) -> impl IntoResponse{ async fn network_settings(State(state): State<SharedState>) -> impl IntoResponse {
let st = state.read().unwrap(); let st = state.read().await;
let name = st.name().unwrap(); let name = st.name().await.unwrap();
let mtu = st.mtu().unwrap(); let mtu = st.mtu().await.unwrap();
let netmask = st.netmask().unwrap(); let netmask = st.netmask().await.unwrap();
let res = Json(json!({ let res = Json(json!({
"name": name, "name": name,
"mtu": mtu, "mtu": mtu,

View file

@ -5,9 +5,6 @@ pub struct TunInterface {
inner: AsyncFd<crate::TunInterface>, inner: AsyncFd<crate::TunInterface>,
} }
unsafe impl Send for TunInterface {
}
impl TunInterface { impl TunInterface {
pub fn new(tun: crate::TunInterface) -> io::Result<Self> { pub fn new(tun: crate::TunInterface) -> io::Result<Self> {
Ok(Self { Ok(Self {