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 {
let logger = Logger(subsystem: "com.hackclub.burrow", category: "General")
var osInitialized = false
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
libburrow.initialize_oslog()
let fild = libburrow.retrieve()
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)
if(!osInitialized){
libburrow.initialize_oslog()
osInitialized=true
}
logger.info("fd: \(fild)")
let network_settings = genNetSec(fild: fild)
logger.info("Network Settings: - ipv4:\(network_settings.ipv4Settings) -mtu: \(network_settings.mtu)")
libburrow.spawn_server()
logger.debug("spawned server")
completionHandler(nil)
}

View file

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

11
Cargo.lock generated
View file

@ -1136,6 +1136,16 @@ dependencies = [
"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]]
name = "once_cell"
version = "1.17.1"
@ -1768,6 +1778,7 @@ dependencies = [
"bytes",
"libc",
"mio",
"num_cpus",
"pin-project-lite",
"socket2",
"tokio-macros",

View file

@ -7,7 +7,7 @@ edition = "2021"
crate-type = ["lib", "staticlib"]
[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"]}
clap = { version = "4.3.2", features = ["derive"] }
env_logger = "0.10"

View file

@ -16,6 +16,8 @@ use tun::TunInterface;
#[cfg(target_vendor = "apple")]
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
#[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::{
borrow::Cow,
collections::HashMap,
sync::{Arc, RwLock},
sync::Arc,
time::Duration,
};
use tokio::sync::RwLock;
use tokio::runtime::Runtime;
use std::net::{Ipv4Addr, SocketAddr};
use axum::handler::HandlerWithoutStateExt;
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>>;
pub async fn serve(ti: TunInterface){
let state = Arc::new(RwLock::new(
ti
));
#[no_mangle]
pub extern "C" fn spawn_server(){
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()
.route("/info", get(network_settings))
.with_state(state);
let port = std::env::var("BURROW_PORT").unwrap_or("3000".to_string());
let sock_addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), port.parse().unwrap());
info!("Listening on {}...", sock_addr);
axum::Server::bind(&sock_addr)
.serve(app_router.into_make_service())
.await
@ -28,11 +75,11 @@ pub async fn serve(ti: TunInterface){
}
#[debug_handler]
async fn network_settings(State(state): State<SharedState>) -> impl IntoResponse{
let st = state.read().unwrap();
let name = st.name().unwrap();
let mtu = st.mtu().unwrap();
let netmask = st.netmask().unwrap();
async fn network_settings(State(state): State<SharedState>) -> impl IntoResponse {
let st = state.read().await;
let name = st.name().await.unwrap();
let mtu = st.mtu().await.unwrap();
let netmask = st.netmask().await.unwrap();
let res = Json(json!({
"name": name,
"mtu": mtu,

View file

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