implement automatic receiving of tun messages from elixir code
This commit is contained in:
parent
7b4d355d1a
commit
486fea2088
10 changed files with 119 additions and 106 deletions
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "p2pchat_transport_tuntapport"
|
||||
name = "p2pchat_transport_gen_tun"
|
||||
version = "0.1.0"
|
||||
authors = []
|
||||
edition = "2021"
|
||||
63
native/p2pchat_transport_gen_tun/src/lib.rs
Normal file
63
native/p2pchat_transport_gen_tun/src/lib.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use std::io;
|
||||
use std::net::Ipv6Addr;
|
||||
|
||||
use rustler::types::tuple::make_tuple;
|
||||
use rustler::{resource_impl, Encoder, NifResult, OwnedBinary, Resource, ResourceArc, Term};
|
||||
use tun_rs::{DeviceBuilder, SyncDevice};
|
||||
|
||||
mod atoms {
|
||||
rustler::atoms! {
|
||||
ok,
|
||||
resource_busy,
|
||||
permission_denied,
|
||||
would_block,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TunHandle {
|
||||
device: SyncDevice,
|
||||
}
|
||||
|
||||
#[resource_impl]
|
||||
impl Resource for TunHandle {}
|
||||
|
||||
#[rustler::nif]
|
||||
fn make_tun_device(env: rustler::Env) -> NifResult<Term> {
|
||||
let device = DeviceBuilder::new()
|
||||
.name("tunP2P")
|
||||
.ipv6(Ipv6Addr::new(0x2001, 0x2f, 0, 0, 0, 0, 0, 1), 28)
|
||||
.packet_information(true)
|
||||
.build_sync()
|
||||
.map_err(map_io_error)?;
|
||||
device.set_nonblocking(true).map_err(map_io_error)?;
|
||||
|
||||
let handle = ResourceArc::new(TunHandle { device });
|
||||
Ok(make_ok_tuple(env, handle))
|
||||
}
|
||||
|
||||
#[rustler::nif]
|
||||
fn tun_recv(env: rustler::Env, handle: ResourceArc<TunHandle>, bufsize: usize) -> NifResult<Term> {
|
||||
let mut buf = OwnedBinary::new(bufsize).expect("Could not allocate receive buffer");
|
||||
let n = handle.device.recv(&mut buf).map_err(map_io_error)?;
|
||||
assert!(buf.realloc(n));
|
||||
let erl_buf = buf.release(env);
|
||||
|
||||
Ok(make_ok_tuple(env, erl_buf))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn map_io_error(error: io::Error) -> rustler::Error {
|
||||
rustler::Error::Term(match error.kind() {
|
||||
io::ErrorKind::ResourceBusy => Box::new(atoms::resource_busy()),
|
||||
io::ErrorKind::PermissionDenied => Box::new(atoms::permission_denied()),
|
||||
io::ErrorKind::WouldBlock => Box::new(atoms::would_block()),
|
||||
e => Box::new(e.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn make_ok_tuple<T: Encoder>(env: rustler::Env, value: T) -> Term {
|
||||
make_tuple(env, &[atoms::ok().encode(env), value.encode(env)])
|
||||
}
|
||||
|
||||
rustler::init!("Elixir.P2pChat.Transport.GenTun");
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
use std::io;
|
||||
use std::net::Ipv6Addr;
|
||||
|
||||
use rustler::Binary;
|
||||
use rustler::NifResult;
|
||||
use rustler::OwnedBinary;
|
||||
use rustler::Resource;
|
||||
use rustler::ResourceArc;
|
||||
use rustler::Error;
|
||||
use tun_rs::DeviceBuilder;
|
||||
use tun_rs::SyncDevice;
|
||||
|
||||
|
||||
mod atoms {
|
||||
rustler::atoms! {
|
||||
ok,
|
||||
would_block,
|
||||
other_error,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TunHandle {
|
||||
device: SyncDevice,
|
||||
}
|
||||
|
||||
#[rustler::resource_impl]
|
||||
impl Resource for TunHandle {}
|
||||
|
||||
#[rustler::nif]
|
||||
fn make_tun_device() -> NifResult<ResourceArc<TunHandle>> {
|
||||
let device = DeviceBuilder::new()
|
||||
.name("tunP2P")
|
||||
.ipv6(Ipv6Addr::new(0x2001, 0x2f, 0, 0, 0, 0, 0, 1), 28)
|
||||
.build_sync()
|
||||
.expect("Could not create tun device");
|
||||
device.set_nonblocking(true).expect("Could not make TUN device nonblocking");
|
||||
|
||||
println!("TUN device {} created", device.name().unwrap());
|
||||
|
||||
let handle = ResourceArc::new(TunHandle { device });
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
#[rustler::nif]
|
||||
fn read(env: rustler::Env, handle: ResourceArc<TunHandle>, length: usize) -> NifResult<Binary> {
|
||||
let mut buf = OwnedBinary::new(length).expect("Could not allocate a buffer from the BEAM");
|
||||
|
||||
let n = match handle.device.recv(&mut buf) {
|
||||
Ok(n) => n,
|
||||
Err(e) => return match e.kind() {
|
||||
io::ErrorKind::WouldBlock => Err(Error::Term(Box::new(atoms::would_block()))),
|
||||
_ => Err(Error::Term(Box::new(atoms::other_error()))),
|
||||
},
|
||||
};
|
||||
println!("Have read {n} bytes");
|
||||
|
||||
let erl_buf = Binary::from_owned(buf, env);
|
||||
Ok(erl_buf)
|
||||
}
|
||||
|
||||
|
||||
rustler::init!("Elixir.P2pChat.Transport.TunTapPort");
|
||||
Loading…
Add table
Add a link
Reference in a new issue