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
13
native/p2pchat_transport_gen_tun/Cargo.toml
Normal file
13
native/p2pchat_transport_gen_tun/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "p2pchat_transport_gen_tun"
|
||||
version = "0.1.0"
|
||||
authors = []
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
rustler = "0.37.4"
|
||||
tun-rs = { version = "2.8.3", default-features = false, features = ["blocking", "experimental"] }
|
||||
|
||||
20
native/p2pchat_transport_gen_tun/README.md
Normal file
20
native/p2pchat_transport_gen_tun/README.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# NIF for P2pChat.Transport.TunTapPort
|
||||
|
||||
## To build the NIF module:
|
||||
|
||||
- Your NIF will now build along with your project.
|
||||
|
||||
## To load the NIF:
|
||||
|
||||
```elixir
|
||||
defmodule P2pChat.Transport.TunTapPort do
|
||||
use Rustler, otp_app: :p2p_chat, crate: "p2pchat_transport_tuntapport"
|
||||
|
||||
# When your NIF is loaded, it will override this function.
|
||||
def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded)
|
||||
end
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
[This](https://github.com/rusterlium/NifIo) is a complete example of a NIF written in Rust.
|
||||
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");
|
||||
Loading…
Add table
Add a link
Reference in a new issue