From 2446dcf05d9caee6a6bf2c07289c5a1690ac4719 Mon Sep 17 00:00:00 2001 From: lilly Date: Fri, 22 May 2026 15:38:11 +0200 Subject: [PATCH] enif_select() shenanigans --- Cargo.lock | 11 +++--- Cargo.toml | 4 ++ native/p2pchat_transport_prim_tun/Cargo.toml | 2 +- native/p2pchat_transport_prim_tun/src/lib.rs | 39 +++++++++++++++++++- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1495f33..67a0d89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "bitflags" @@ -490,10 +490,10 @@ dependencies = [ [[package]] name = "rustler" version = "0.37.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875c8fe88089b9bbc0977385e107d35bfae740c6b0734e60a1e9cc82d0017f49" +source = "git+https://github.com/lilioid/rustler.git?branch=master#fca9102702b878e7d8f05cf905552288206fa310" dependencies = [ "inventory", + "libc", "libloading", "regex-lite", "rustler_codegen", @@ -502,8 +502,7 @@ dependencies = [ [[package]] name = "rustler_codegen" version = "0.37.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb5848e9c4cf3796f190d9b4516523af27f3444a3af1771f20465f6586d40b2" +source = "git+https://github.com/lilioid/rustler.git?branch=master#fca9102702b878e7d8f05cf905552288206fa310" dependencies = [ "heck", "inventory", diff --git a/Cargo.toml b/Cargo.toml index 5d4615c..8a3fe92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,3 +2,7 @@ resolver = "2" members = ["native/p2pchat_transport_prim_tun"] + +[workspace.dependencies] +rustler = { version = "0.37.4", git = "https://github.com/lilioid/rustler.git", branch="master" } + diff --git a/native/p2pchat_transport_prim_tun/Cargo.toml b/native/p2pchat_transport_prim_tun/Cargo.toml index f043ec6..700d6e1 100644 --- a/native/p2pchat_transport_prim_tun/Cargo.toml +++ b/native/p2pchat_transport_prim_tun/Cargo.toml @@ -8,6 +8,6 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rustler = "0.37.4" +rustler = { workspace = true } tun-rs = { version = "2.8.3", default-features = false, features = ["blocking", "experimental"] } diff --git a/native/p2pchat_transport_prim_tun/src/lib.rs b/native/p2pchat_transport_prim_tun/src/lib.rs index 7d13c82..3debf05 100644 --- a/native/p2pchat_transport_prim_tun/src/lib.rs +++ b/native/p2pchat_transport_prim_tun/src/lib.rs @@ -1,7 +1,9 @@ use std::io; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::ops::Deref; +use std::os::fd::AsRawFd; +use rustler::sys::{ErlNifEvent, ERL_NIF_SELECT_STOP}; use rustler::types::tuple::{get_tuple, make_tuple}; use rustler::{ resource_impl, Binary, Decoder, Encoder, NifResult, OwnedBinary, Resource, ResourceArc, Term, @@ -11,6 +13,7 @@ use tun_rs::{DeviceBuilder, SyncDevice}; mod atoms { rustler::atoms! { ok, + undefined, resource_busy, permission_denied, would_block, @@ -92,7 +95,12 @@ impl<'a> Decoder<'a> for WrappedIpAddr { } #[resource_impl] -impl Resource for TunHandle {} +impl Resource for TunHandle { + fn stop<'a>(&'a self, _env: rustler::Env<'a>, event: ErlNifEvent, is_direct_call: bool) { + println!("event: {event:?}"); + println!("is_direct_call: {is_direct_call:?}"); + } +} #[rustler::nif] fn make_tun_device(env: rustler::Env, packet_info: bool) -> NifResult { @@ -101,9 +109,10 @@ fn make_tun_device(env: rustler::Env, packet_info: bool) -> NifResult { .packet_information(packet_info) .build_sync() .map_err(map_io_error)?; - device.set_nonblocking(true).map_err(map_io_error)?; + // device.set_nonblocking(true).map_err(map_io_error)?; let handle = ResourceArc::new(TunHandle { device }); + register_io(env, &handle); Ok(make_ok_tuple(env, handle)) } @@ -198,6 +207,32 @@ fn set_mtu(handle: ResourceArc, mtu: u16) -> NifResult<()> { handle.device.set_mtu(mtu).map_err(map_io_error) } +/// Register pending IO with the erlang vm to later receive a callback when +/// something happened to the device and IO is available. +fn register_io(env: rustler::Env, handle: &ResourceArc) { + // Safety: yolo! I have no idea what I'm doing + unsafe { + let enif_env = env.as_c_arg(); + let enif_event: ErlNifEvent = handle.device.as_raw_fd(); + let enif_flags = rustler::sys::ERL_NIF_SELECT_READ; + let enif_obj = handle.as_c_arg(); + let enif_pid = std::ptr::null(); + let enif_ref = atoms::undefined().to_term(env).as_c_arg(); + rustler::sys::enif_select( + enif_env, enif_event, enif_flags, enif_obj, enif_pid, enif_ref, + ); + + rustler::sys::enif_select( + enif_env, + enif_event, + ERL_NIF_SELECT_STOP, + enif_obj, + enif_pid, + enif_ref, + ); + } +} + fn map_io_error(error: io::Error) -> rustler::Error { rustler::Error::Term(match error.kind() { io::ErrorKind::ResourceBusy => Box::new(atoms::resource_busy()),