use std::ffi::{c_char, CStr};
use std::net::SocketAddr;
use std::ptr;
use std::slice;
use tokio::runtime::Runtime;
use crate::net::fast::{SecureSocket, SecureEvent};
use crate::net::fast::delta::{DeltaEncoder, DeltaDecoder};
#[repr(C)]
pub enum FastNetEventType {
None = 0,
Connected = 1,
Data = 2,
Disconnected = 3,
Error = 4,
}
#[repr(C)]
pub struct FastNetEvent {
pub event_type: FastNetEventType,
pub peer_id: u16,
pub channel: u8,
pub data: *mut u8,
pub data_len: u32,
pub error_code: i32,
}
impl Default for FastNetEvent {
fn default() -> Self {
Self {
event_type: FastNetEventType::None,
peer_id: 0,
channel: 0,
data: ptr::null_mut(),
data_len: 0,
error_code: 0,
}
}
}
pub struct FastNetClient {
runtime: Runtime,
socket: Option<SecureSocket>,
last_data: Option<Vec<u8>>,
server_peer_id: u16,
}
pub struct FastNetServer {
runtime: Runtime,
socket: Option<SecureSocket>,
last_data: Option<Vec<u8>>,
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_client_connect(
host: *const c_char,
port: u16,
) -> *mut FastNetClient {
if host.is_null() {
return ptr::null_mut();
}
let host_str = unsafe {
match CStr::from_ptr(host).to_str() {
Ok(s) => s,
Err(_) => return ptr::null_mut(),
}
};
let addr: SocketAddr = match format!("{}:{}", host_str, port).parse() {
Ok(a) => a,
Err(_) => return ptr::null_mut(),
};
let runtime = match Runtime::new() {
Ok(rt) => rt,
Err(_) => return ptr::null_mut(),
};
let socket = runtime.block_on(async {
SecureSocket::connect(addr).await.ok()
});
if socket.is_none() {
return ptr::null_mut();
}
let client = Box::new(FastNetClient {
runtime,
socket,
last_data: None,
server_peer_id: 0,
});
Box::into_raw(client)
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_client_disconnect(client: *mut FastNetClient) {
if !client.is_null() {
unsafe {
drop(Box::from_raw(client));
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_client_send(
client: *mut FastNetClient,
channel: u8,
data: *const u8,
data_len: u32,
) -> i32 {
if client.is_null() || data.is_null() {
return -1;
}
let client = unsafe { &mut *client };
let data_slice = unsafe { slice::from_raw_parts(data, data_len as usize) };
if let Some(ref mut socket) = client.socket {
let peer_id = client.server_peer_id;
let result = client.runtime.block_on(async {
socket.send(peer_id, channel, data_slice.to_vec()).await
});
match result {
Ok(_) => 0,
Err(_) => -2,
}
} else {
-3
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_client_poll(
client: *mut FastNetClient,
event: *mut FastNetEvent,
) -> bool {
if client.is_null() || event.is_null() {
return false;
}
let client = unsafe { &mut *client };
let event = unsafe { &mut *event };
*event = FastNetEvent::default();
client.last_data = None;
if let Some(ref mut socket) = client.socket {
let events = client.runtime.block_on(async {
socket.poll().await.unwrap_or_default()
});
if let Some(e) = events.into_iter().next() {
match e {
SecureEvent::Connected(peer_id) => {
event.event_type = FastNetEventType::Connected;
event.peer_id = peer_id;
client.server_peer_id = peer_id;
return true;
}
SecureEvent::Data(peer_id, channel, data) => {
event.event_type = FastNetEventType::Data;
event.peer_id = peer_id;
event.channel = channel;
event.data_len = data.len() as u32;
client.last_data = Some(data);
if let Some(ref d) = client.last_data {
event.data = d.as_ptr() as *mut u8;
}
return true;
}
SecureEvent::Disconnected(peer_id) => {
event.event_type = FastNetEventType::Disconnected;
event.peer_id = peer_id;
return true;
}
}
}
}
false
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_client_rtt_us(client: *mut FastNetClient) -> u64 {
if client.is_null() {
return 0;
}
let client = unsafe { &*client };
if let Some(ref socket) = client.socket {
socket.peer_rtt(0).map(|d| d.as_micros() as u64).unwrap_or(0)
} else {
0
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_server_create(
udp_port: u16,
tcp_port: u16,
cert_path: *const c_char,
key_path: *const c_char,
) -> *mut FastNetServer {
if cert_path.is_null() || key_path.is_null() {
return ptr::null_mut();
}
let cert_str = unsafe {
match CStr::from_ptr(cert_path).to_str() {
Ok(s) => s,
Err(_) => return ptr::null_mut(),
}
};
let key_str = unsafe {
match CStr::from_ptr(key_path).to_str() {
Ok(s) => s,
Err(_) => return ptr::null_mut(),
}
};
let runtime = match Runtime::new() {
Ok(rt) => rt,
Err(_) => return ptr::null_mut(),
};
let socket = runtime.block_on(async {
use std::fs::File;
use std::io::BufReader;
use rustls_pemfile::{certs, private_key};
let cert_file = File::open(cert_str).ok()?;
let key_file = File::open(key_str).ok()?;
let certs: Vec<_> = certs(&mut BufReader::new(cert_file))
.filter_map(|r| r.ok())
.collect();
let key = private_key(&mut BufReader::new(key_file)).ok()??;
let udp_addr: SocketAddr = format!("0.0.0.0:{}", udp_port).parse().ok()?;
let tcp_addr: SocketAddr = format!("0.0.0.0:{}", tcp_port).parse().ok()?;
SecureSocket::bind_server(udp_addr, tcp_addr, certs, key).await.ok()
});
if socket.is_none() {
return ptr::null_mut();
}
let server = Box::new(FastNetServer {
runtime,
socket,
last_data: None,
});
Box::into_raw(server)
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_server_destroy(server: *mut FastNetServer) {
if !server.is_null() {
unsafe {
drop(Box::from_raw(server));
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_server_send(
server: *mut FastNetServer,
peer_id: u16,
channel: u8,
data: *const u8,
data_len: u32,
) -> i32 {
if server.is_null() || data.is_null() {
return -1;
}
let server = unsafe { &mut *server };
let data_slice = unsafe { slice::from_raw_parts(data, data_len as usize) };
if let Some(ref mut socket) = server.socket {
let result = server.runtime.block_on(async {
socket.send(peer_id, channel, data_slice.to_vec()).await
});
match result {
Ok(_) => 0,
Err(_) => -2,
}
} else {
-3
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_server_poll(
server: *mut FastNetServer,
event: *mut FastNetEvent,
) -> bool {
if server.is_null() || event.is_null() {
return false;
}
let server = unsafe { &mut *server };
let event = unsafe { &mut *event };
*event = FastNetEvent::default();
server.last_data = None;
if let Some(ref mut socket) = server.socket {
let events = server.runtime.block_on(async {
socket.poll().await.unwrap_or_default()
});
if let Some(e) = events.into_iter().next() {
match e {
SecureEvent::Connected(peer_id) => {
event.event_type = FastNetEventType::Connected;
event.peer_id = peer_id;
return true;
}
SecureEvent::Data(peer_id, channel, data) => {
event.event_type = FastNetEventType::Data;
event.peer_id = peer_id;
event.channel = channel;
event.data_len = data.len() as u32;
server.last_data = Some(data);
if let Some(ref d) = server.last_data {
event.data = d.as_ptr() as *mut u8;
}
return true;
}
SecureEvent::Disconnected(peer_id) => {
event.event_type = FastNetEventType::Disconnected;
event.peer_id = peer_id;
return true;
}
}
}
}
false
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_server_peer_count(server: *mut FastNetServer) -> u32 {
if server.is_null() {
return 0;
}
let server = unsafe { &*server };
if let Some(ref socket) = server.socket {
socket.peer_count() as u32
} else {
0
}
}
pub struct FastNetDeltaEncoder {
encoder: DeltaEncoder,
output_buffer: Vec<u8>,
}
pub struct FastNetDeltaDecoder {
decoder: DeltaDecoder,
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_delta_encoder_create() -> *mut FastNetDeltaEncoder {
let encoder = Box::new(FastNetDeltaEncoder {
encoder: DeltaEncoder::new(),
output_buffer: vec![0u8; 65536], });
Box::into_raw(encoder)
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_delta_encoder_destroy(encoder: *mut FastNetDeltaEncoder) {
if !encoder.is_null() {
unsafe { drop(Box::from_raw(encoder)); }
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_delta_encode(
encoder: *mut FastNetDeltaEncoder,
old_state: *const u8,
old_len: u32,
new_state: *const u8,
new_len: u32,
output: *mut u8,
output_capacity: u32,
output_len: *mut u32,
) -> i32 {
if encoder.is_null() || old_state.is_null() || new_state.is_null()
|| output.is_null() || output_len.is_null() {
return -1;
}
let encoder = unsafe { &mut *encoder };
let old_slice = unsafe { slice::from_raw_parts(old_state, old_len as usize) };
let new_slice = unsafe { slice::from_raw_parts(new_state, new_len as usize) };
match encoder.encoder.encode(old_slice, new_slice) {
Some((delta, size)) => {
if size > output_capacity as usize {
return -2;
}
unsafe {
ptr::copy_nonoverlapping(delta.as_ptr(), output, size);
*output_len = size as u32;
}
0
}
None => -3,
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_delta_decoder_create() -> *mut FastNetDeltaDecoder {
let decoder = Box::new(FastNetDeltaDecoder {
decoder: DeltaDecoder::new(),
});
Box::into_raw(decoder)
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_delta_decoder_destroy(decoder: *mut FastNetDeltaDecoder) {
if !decoder.is_null() {
unsafe { drop(Box::from_raw(decoder)); }
}
}
#[unsafe(no_mangle)]
pub extern "C" fn fastnet_delta_apply(
decoder: *mut FastNetDeltaDecoder,
delta: *const u8,
delta_len: u32,
state: *mut u8,
state_len: u32,
) -> i32 {
if decoder.is_null() || delta.is_null() || state.is_null() {
return -1;
}
let decoder = unsafe { &mut *decoder };
let delta_slice = unsafe { slice::from_raw_parts(delta, delta_len as usize) };
let state_slice = unsafe { slice::from_raw_parts_mut(state, state_len as usize) };
match decoder.decoder.apply(delta_slice, state_slice) {
Ok(_) => 0,
Err(_) => -3,
}
}