implement minimal NIF to create and read from a TUN device
This commit is contained in:
parent
72a4f2ff8f
commit
7b4d355d1a
12 changed files with 963 additions and 1 deletions
13
native/p2pchat_transport_tuntapport/Cargo.toml
Normal file
13
native/p2pchat_transport_tuntapport/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "p2pchat_transport_tuntapport"
|
||||
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_tuntapport/README.md
Normal file
20
native/p2pchat_transport_tuntapport/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.
|
||||
62
native/p2pchat_transport_tuntapport/src/lib.rs
Normal file
62
native/p2pchat_transport_tuntapport/src/lib.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
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