Rust plugin
Recent experiments have shown that it is possible to bind any language that
compile to native code to proxenet
, as long as it exports some specific
symbols. This relies on one of most powerful advantages of proxenet
, that is
being 100% written in C
.
This page will detail how to write proxenet
plugins in the Rust
.
Rust
will use its compiler (rustc
) to generate native code that respects its
paradigms (multi-threadable, memory and type safe). Since rust
allows to
generate shared objects, and explicitly exposing some exported symbols, binding
it on proxenet
did not require any change to the C
interface. The challenge
consisted in exporting the structure from the C
level (and potentially unsafe)
to rust
structure.
As a result, you can now use the following skeleton for writing your rust
plugin for proxenet
.
Enjoy!
Plugin skeleton
//
// Dummy Rust plugin for proxenet
// by @_hugsy_
//
// Compile with:
// $ rustc -o MyPlugin.so Myplugin.rs
//
#![crate_type = "dylib"]
use std::mem;
//
// proxenet request hook for Rust
// This function is type and memory safe.
//
fn rust_request_hook(request_id: u32, request: Vec<u8>, uri: String) -> Vec<u8>
{
// Play your funky Rust here white boy!
return request;
}
//
// proxenet response hook for Rust
// This function is type and memory safe.
//
fn rust_response_hook(response_id: u32, response: Vec<u8>, uri: String) -> Vec<u8>
{
return response;
}
//
// Poor man strlen() compat function for Rust
//
fn rust_strlen(src: *const u8) -> usize
{
let mut i = 0;
let mut do_loop = true;
while do_loop {
let c = unsafe { *src.offset(i) as char };
if c == '\x00' { do_loop = false; }
else { i += 1; }
}
return i as usize;
}
//
// This function is used to transform and dispatch C compatible data type (unsafe) to
// Rust valid types, dispatch to the right function ({request,response}_hook).
//
fn generic_hook(rid: u32, buf: *mut u8, uri: *mut u8, buflen: *mut usize, is_request: bool) -> *mut u8
{
unsafe {
let rust_buf = Vec::from_raw_parts(buf, *buflen, *buflen);
let rust_urilen = rust_strlen( uri );
let rust_uri = String::from_raw_parts(uri, rust_urilen, rust_urilen);
let ret;
if is_request {
ret = rust_request_hook (rid, rust_buf, rust_uri);
} else {
ret = rust_response_hook(rid, rust_buf, rust_uri);
}
*buflen = ret.len();
return mem::transmute(&ret);
}
}
#[no_mangle]
pub extern fn proxenet_request_hook(request_id: u32, request: *mut u8, uri: *mut u8, request_len: *mut usize) -> *mut u8
{
return generic_hook(request_id, request, uri, request_len, true);
}
#[no_mangle]
pub extern fn proxenet_response_hook(response_id: u32, response: *mut u8, uri: *mut u8, response_len: *mut usize) -> *mut u8
{
return generic_hook(response_id, response, uri, response_len, false);
}
Note: not being a professional
rust
developper, maybe my approach is sub optimal. If so, shoot me an email with your improvement :)
The C
plugin interface of proxenet
must be used to load rust
compiled
plugins. So all the plugins must be compiled first, and the shared library
must be suffixed with .so
.
$ rustc -o MyPlugin.so MyPlugin.rs
Move your compiled plugin to proxenet
plugin directory, and fire it up.