Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/libknet/bindings/rust/src/knet_bindings.rs b/libknet/bindings/rust/src/knet_bindings.rs
index 2b18ebcc..4bbf999e 100644
--- a/libknet/bindings/rust/src/knet_bindings.rs
+++ b/libknet/bindings/rust/src/knet_bindings.rs
@@ -1,2560 +1,2560 @@
// libknet interface for Rust
// Copyright (C) 2021-2023 Red Hat, Inc.
//
// All rights reserved.
//
// Author: Christine Caulfield (ccaulfi@redhat.com)
//
#![allow(clippy::too_many_arguments)]
#![allow(clippy::collapsible_else_if)]
// For the code generated by bindgen
use crate::sys::libknet as ffi;
use std::ffi::{CString, CStr};
use std::sync::mpsc::*;
use std::ptr::{copy_nonoverlapping, null, null_mut};
use std::sync::Mutex;
use std::collections::HashMap;
use std::io::{Result, Error, ErrorKind};
use std::os::raw::{c_void, c_char, c_uchar, c_uint};
use std::mem::size_of;
use std::net::SocketAddr;
use std::fmt;
use std::thread::spawn;
use std::time::{Duration, SystemTime};
use os_socketaddr::OsSocketAddr;
#[derive(Copy, Clone, PartialEq, Eq)]
/// The ID of a host known to knet.
pub struct HostId {
host_id: u16,
}
impl HostId {
pub fn new(id: u16) -> HostId
{
HostId{host_id: id}
}
pub fn to_u16(self: HostId) -> u16
{
self.host_id
}
}
impl fmt::Display for HostId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,"{}", self.host_id)?;
Ok(())
}
}
pub enum TxRx {
Tx = 0,
Rx = 1
}
impl TxRx {
pub fn new (tx_rx: u8) -> TxRx
{
match tx_rx {
1 => TxRx::Rx,
_ => TxRx::Tx
}
}
}
impl fmt::Display for TxRx {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TxRx::Tx => write!(f, "Tx"),
TxRx::Rx => write!(f, "Rx"),
}
}
}
bitflags! {
/// Flags passed into [handle_new]
pub struct HandleFlags: u64
{
const PRIVILEGED = 1;
const NONE = 0;
}
}
bitflags! {
/// Flags passed into [link_set_config]
pub struct LinkFlags: u64
{
const TRAFFICHIPRIO = 1;
const NONE = 0;
}
}
/// for passing to [handle_crypto_set_config]
pub struct CryptoConfig<'a> {
pub crypto_model: String,
pub crypto_cipher_type: String,
pub crypto_hash_type: String,
pub private_key: &'a [u8],
}
/// for passing to [handle_compress]
pub struct CompressConfig {
pub compress_model: String,
pub compress_threshold: u32,
pub compress_level: i32,
}
/// Return value from packet filter
pub enum FilterDecision {
Discard,
Unicast,
Multicast
}
impl FilterDecision {
pub fn to_i32(self: &FilterDecision) -> i32
{
match self {
FilterDecision::Discard => -1,
FilterDecision::Unicast => 0,
FilterDecision::Multicast => 1,
}
}
}
impl fmt::Display for FilterDecision {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FilterDecision::Discard => write!(f, "Discard"),
FilterDecision::Unicast => write!(f, "Unicast"),
FilterDecision::Multicast => write!(f, "Multicast"),
}
}
}
// Used to convert a knet_handle_t into one of ours
lazy_static! {
static ref HANDLE_HASH: Mutex<HashMap<u64, PrivHandle>> = Mutex::new(HashMap::new());
}
fn get_errno() -> i32
{
match Error::last_os_error().raw_os_error() {
Some(e) => e,
None => libc::EINVAL,
}
}
/// Callback from [handle_enable_sock_notify]
pub type SockNotifyFn = fn(private_data: u64,
datafd: i32,
channel: i8,
txrx: TxRx,
Result<()>);
/// Callback called when packets arrive/are sent [handle_enable_filter]
pub type FilterFn = fn(private_data: u64,
outdata: &[u8],
txrx: TxRx,
this_host_id: HostId,
src_host_id: HostId,
channel: &mut i8,
dst_host_ids: &mut Vec<HostId>) -> FilterDecision;
/// Callback called when PMTU changes, see [handle_enable_pmtud_notify]
pub type PmtudNotifyFn = fn(private_data: u64,
data_mtu: u32);
/// Called when the onwire version number for a node changes, see [handle_enable_onwire_ver_notify]
pub type OnwireNotifyFn = fn(private_data: u64,
onwire_min_ver: u8,
onwire_max_ver: u8,
onwire_ver: u8);
/// Called when a host status changes, see [host_enable_status_change_notify]
pub type HostStatusChangeNotifyFn = fn(private_data: u64,
host_id: HostId,
reachable: bool,
remote: bool,
external: bool);
/// Called when a link status changes, see [link_enable_status_change_notify]
pub type LinkStatusChangeNotifyFn = fn(private_data: u64,
host_id: HostId,
link_id: u8,
connected: bool,
remote: bool,
external: bool);
// Called from knet, we work out where to route it to and convert params
extern "C" fn rust_sock_notify_fn(
private_data: *mut c_void,
datafd: i32,
channel: i8,
tx_rx: u8,
error: i32,
errorno: i32)
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get(&(private_data as u64)) {
let res = if error == 0 {
Ok(())
} else {
Err(Error::from_raw_os_error(errorno))
};
// Call user fn
if let Some(f) = h.sock_notify_fn {
f(h.sock_notify_private_data,
datafd,
channel,
TxRx::new(tx_rx),
res);
}
}
}
// Called from knet, we work out where to route it to and convert params
extern "C" fn rust_filter_fn(
private_data: *mut c_void,
outdata: *const c_uchar,
outdata_len: isize,
tx_rx: u8,
this_host_id: u16,
src_host_id: u16,
channel: *mut i8,
dst_host_ids: *mut u16,
dst_host_ids_entries: *mut usize) -> i32
{
let mut ret : i32 = -1;
if let Some(h) = HANDLE_HASH.lock().unwrap().get(&(private_data as u64)) {
// Is there is filter fn?
if let Some(f) = h.filter_fn {
let data : &[u8] = unsafe {
std::slice::from_raw_parts(outdata as *const u8, outdata_len as usize)
};
let mut r_channel = unsafe {*channel};
let mut hosts_vec = Vec::<HostId>::new();
// Call Rust callback
ret = f(h.filter_private_data,
data,
TxRx::new(tx_rx),
HostId{host_id: this_host_id},
HostId{host_id: src_host_id},
&mut r_channel,
&mut hosts_vec).to_i32();
// Pass back mutable params dst_hosts
unsafe {
*channel = r_channel;
*dst_host_ids_entries = hosts_vec.len();
let mut retvec = dst_host_ids;
for i in &hosts_vec {
*retvec = i.host_id;
retvec = retvec.offset(1); // next entry
}
}
}
}
ret
}
// Called from knet, we work out where to route it to and convert params
extern "C" fn rust_pmtud_notify_fn(
private_data: *mut c_void,
data_mtu: u32)
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get(&(private_data as u64)) {
// Call user fn
if let Some(f) = h.pmtud_notify_fn {
f(h.pmtud_notify_private_data, data_mtu);
}
}
}
// Called from knet, we work out where to route it to and convert params
extern "C" fn rust_onwire_notify_fn(
private_data: *mut c_void,
onwire_min_ver: u8,
onwire_max_ver: u8,
onwire_ver: u8)
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get(&(private_data as u64)) {
// Call user fn
if let Some(f) = h.onwire_notify_fn {
f(h.onwire_notify_private_data,
onwire_min_ver,
onwire_max_ver,
onwire_ver);
}
}
}
// Called from knet, we work out where to route it to and convert params
extern "C" fn rust_host_status_change_notify_fn(
private_data: *mut c_void,
host_id: u16,
reachable: u8,
remote: u8,
external: u8)
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get(&(private_data as u64)) {
// Call user fn
if let Some(f) = h.host_status_change_notify_fn {
f(h.host_status_change_notify_private_data,
HostId{host_id},
crate::u8_to_bool(reachable),
crate::u8_to_bool(remote),
crate::u8_to_bool(external));
}
}
}
// Called from knet, we work out where to route it to and convert params
extern "C" fn rust_link_status_change_notify_fn(
private_data: *mut c_void,
host_id: u16,
link_id: u8,
connected: u8,
remote: u8,
external: u8)
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get(&(private_data as u64)) {
// Call user fn
if let Some(f) = h.link_status_change_notify_fn {
f(h.link_status_change_notify_private_data,
HostId{host_id},
link_id,
crate::u8_to_bool(connected),
crate::u8_to_bool(remote),
crate::u8_to_bool(external));
}
}
}
// Logging thread
fn logging_thread(knet_pipe: i32, sender: Sender<LogMsg>)
{
let mut logbuf = ffi::knet_log_msg {msg: [0; 254],
subsystem: 0,
msglevel: 0,
knet_h: 0 as ffi::knet_handle_t};
// Make it blocking
unsafe { libc::fcntl(knet_pipe, libc::F_SETFL,
libc::fcntl(knet_pipe, libc::F_GETFL, 0) & !libc::O_NONBLOCK)};
loop {
let msglen = unsafe {libc::read(knet_pipe, &mut logbuf as *mut _ as *mut c_void,
size_of::<ffi::knet_log_msg>())};
if msglen < 1 {
unsafe { libc::close(knet_pipe); }
// EOF on pipe, handle is closed.
return;
}
if msglen == size_of::<ffi::knet_log_msg>() as isize {
let rmsg = LogMsg {
msg: crate::string_from_bytes_safe(logbuf.msg.as_ptr(), 254),
subsystem: SubSystem::new(logbuf.subsystem),
level: LogLevel::new(logbuf.msglevel),
handle: Handle{knet_handle: logbuf.knet_h as u64}};
if let Err(e) = sender.send(rmsg) {
println!("Error sending log message: {e}");
}
}
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
/// a handle into the knet library, returned from [handle_new]
pub struct Handle {
knet_handle: u64,
}
// Private version of knet handle, contains all the callback data so
// we only need to access it in the calback functions, making the rest
// a bit quicker & neater
struct PrivHandle {
log_fd: i32,
sock_notify_fn: Option<SockNotifyFn>,
sock_notify_private_data: u64,
filter_fn: Option<FilterFn>,
filter_private_data: u64,
pmtud_notify_fn: Option<PmtudNotifyFn>,
pmtud_notify_private_data: u64,
onwire_notify_fn: Option<OnwireNotifyFn>,
onwire_notify_private_data: u64,
host_status_change_notify_fn: Option<HostStatusChangeNotifyFn>,
host_status_change_notify_private_data: u64,
link_status_change_notify_fn: Option<LinkStatusChangeNotifyFn>,
link_status_change_notify_private_data: u64,
}
/// A knet logging message returned down the log_sender channel set in [handle_new]
pub struct LogMsg {
pub msg: String,
pub subsystem: SubSystem,
pub level: LogLevel,
pub handle: Handle,
}
/// Initialise the knet library, returns a handle for use with the other API calls
pub fn handle_new(host_id: &HostId,
log_sender: Option<Sender<LogMsg>>,
default_log_level: LogLevel,
flags: HandleFlags) -> Result<Handle>
{
// If a log sender was passed, make an FD & thread for knet
let log_fd = match log_sender {
Some(s) => {
let mut pipes = [0i32; 2];
if unsafe {libc::pipe(pipes.as_mut_ptr())} != 0 {
return Err(Error::last_os_error());
}
spawn(move || logging_thread(pipes[0], s));
pipes[1]
},
None => 0
};
let res = unsafe {
ffi::knet_handle_new(host_id.host_id,
log_fd,
default_log_level.to_u8(),
flags.bits)
};
if res.is_null() {
Err(Error::last_os_error())
} else {
let rhandle = PrivHandle{log_fd,
sock_notify_fn: None,
sock_notify_private_data: 0u64,
filter_fn: None,
filter_private_data: 0u64,
pmtud_notify_fn: None,
pmtud_notify_private_data: 0u64,
onwire_notify_fn: None,
onwire_notify_private_data: 0u64,
host_status_change_notify_fn: None,
host_status_change_notify_private_data: 0u64,
link_status_change_notify_fn: None,
link_status_change_notify_private_data: 0u64,
};
HANDLE_HASH.lock().unwrap().insert(res as u64, rhandle);
Ok(Handle{knet_handle: res as u64})
}
}
/// Finish with knet, frees the handle returned by [handle_new]
pub fn handle_free(handle: Handle) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_free(handle.knet_handle as ffi::knet_handle_t)
};
if res == 0 {
// Close the log fd as knet doesn't "do ownership" and this will shut down
// our logging thread.
if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(handle.knet_handle)) {
unsafe {
libc::close(h.log_fd);
};
}
HANDLE_HASH.lock().unwrap().remove(&handle.knet_handle);
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Enable notifications of socket state changes, set callback to 'None' to disable
pub fn handle_enable_sock_notify(handle: Handle,
private_data: u64,
sock_notify_fn: Option<SockNotifyFn>) -> Result<()>
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(handle.knet_handle)) {
h.sock_notify_private_data = private_data;
h.sock_notify_fn = sock_notify_fn;
let res = match sock_notify_fn {
Some(_f) =>
unsafe {
ffi::knet_handle_enable_sock_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
Some(rust_sock_notify_fn))
},
None =>
unsafe {
ffi::knet_handle_enable_sock_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
None)
},
};
if res == 0 {
return Ok(());
} else {
return Err(Error::last_os_error());
}
}
Err(Error::new(ErrorKind::Other, "Rust handle not found"))
}
/// Add a data FD to knet. if datafd is 0 then knet will allocate one for you.
pub fn handle_add_datafd(handle: Handle, datafd: i32, channel: i8) -> Result<(i32, i8)>
{
let mut c_datafd = datafd;
let mut c_channel = channel;
let res = unsafe {
ffi::knet_handle_add_datafd(handle.knet_handle as ffi::knet_handle_t,
&mut c_datafd,
&mut c_channel)
};
if res == 0 {
Ok((c_datafd, c_channel))
} else {
Err(Error::last_os_error())
}
}
/// Remove a datafd from knet
pub fn handle_remove_datafd(handle: Handle, datafd: i32) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_remove_datafd(handle.knet_handle as ffi::knet_handle_t,
datafd)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Returns the channel associated with data fd
pub fn handle_get_channel(handle: Handle, datafd: i32) -> Result<i8>
{
let mut c_channel = 0i8;
let res = unsafe {
ffi::knet_handle_get_channel(handle.knet_handle as ffi::knet_handle_t,
datafd, &mut c_channel)
};
if res == 0 {
Ok(c_channel)
} else {
Err(Error::last_os_error())
}
}
/// Returns the data FD associated with a channel
pub fn handle_get_datafd(handle: Handle, channel: i8) -> Result<i32>
{
let mut c_datafd = 0i32;
let res = unsafe {
ffi::knet_handle_get_datafd(handle.knet_handle as ffi::knet_handle_t,
channel, &mut c_datafd)
};
if res == 0 {
Ok(c_datafd)
} else {
Err(Error::last_os_error())
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum DefragReclaimPolicy {
Average = 0,
Absolute = 1
}
impl DefragReclaimPolicy {
pub fn new (policy: u32) -> DefragReclaimPolicy {
{
match policy {
1 => DefragReclaimPolicy::Absolute,
_ => DefragReclaimPolicy::Average,
}
}
}
pub fn to_u32 (&self) -> u32 {
{
match self {
DefragReclaimPolicy::Absolute => 1,
DefragReclaimPolicy::Average => 0,
}
}
}
}
impl fmt::Display for DefragReclaimPolicy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DefragReclaimPolicy::Absolute => write!(f, "Absolute"),
DefragReclaimPolicy::Average => write!(f, "Average"),
}
}
}
/// Configure the defrag buffer parameters - applies to all hosts
pub fn handle_set_host_defrag_bufs(handle: Handle, min_defrag_bufs: u16, max_defrag_bufs: u16,
shrink_threshold: u8,
reclaim_policy: DefragReclaimPolicy) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_set_host_defrag_bufs(handle.knet_handle as ffi::knet_handle_t,
min_defrag_bufs, max_defrag_bufs,
shrink_threshold,
reclaim_policy.to_u32())
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get the defrag buffer parameters.
/// Returns (min_defrag_bufs, max_defrag_bufs, shrink_threshold, usage_samples, usage_samples_timespan, reclaim_policy)
pub fn handle_get_host_defrag_bufs(handle: Handle) -> Result<(u16, u16, u8, DefragReclaimPolicy)>
{
let mut min_defrag_bufs: u16 = 0;
let mut max_defrag_bufs: u16 = 0;
let mut shrink_threshold: u8 = 0;
let mut reclaim_policy: u32 = 0;
let res = unsafe {
ffi::knet_handle_get_host_defrag_bufs(handle.knet_handle as ffi::knet_handle_t,
&mut min_defrag_bufs, &mut max_defrag_bufs,
&mut shrink_threshold,
&mut reclaim_policy)
};
if res == 0 {
Ok((min_defrag_bufs, max_defrag_bufs,
shrink_threshold,
DefragReclaimPolicy::new(reclaim_policy)))
} else {
Err(Error::last_os_error())
}
}
/// Receive messages from knet
pub fn recv(handle: Handle, buf: &[u8], channel: i8) -> Result<isize>
{
let res = unsafe {
ffi::knet_recv(handle.knet_handle as ffi::knet_handle_t,
buf.as_ptr() as *mut c_char,
buf.len(),
channel)
};
if res >= 0 {
Ok(res)
} else {
if get_errno() == libc::EAGAIN {
Err(Error::new(ErrorKind::WouldBlock, "Try again"))
} else {
Err(Error::last_os_error())
}
}
}
/// Send messages knet
pub fn send(handle: Handle, buf: &[u8], channel: i8) -> Result<isize>
{
let res = unsafe {
ffi::knet_send(handle.knet_handle as ffi::knet_handle_t,
buf.as_ptr() as *const c_char,
buf.len(),
channel)
};
if res >= 0 {
Ok(res)
} else {
if get_errno() == libc::EAGAIN {
Err(Error::new(ErrorKind::WouldBlock, "Try again"))
} else {
Err(Error::last_os_error())
}
}
}
/// Send messages to knet and wait till they have gone
pub fn send_sync(handle: Handle, buf: &[u8], channel: i8) -> Result<()>
{
let res = unsafe {
ffi::knet_send_sync(handle.knet_handle as ffi::knet_handle_t,
buf.as_ptr() as *const c_char,
buf.len(),
channel)
};
if res == 0 {
Ok(())
} else {
if get_errno() == libc::EAGAIN {
Err(Error::new(ErrorKind::WouldBlock, "Try again"))
} else {
Err(Error::last_os_error())
}
}
}
/// Enable the packet filter. pass 'None' as the callback to disable.
pub fn handle_enable_filter(handle: Handle,
private_data: u64,
filter_fn: Option<FilterFn>) -> Result<()>
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(handle.knet_handle)) {
h.filter_private_data = private_data;
h.filter_fn = filter_fn;
let res = match filter_fn {
Some(_f) =>
unsafe {
ffi::knet_handle_enable_filter(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
Some(rust_filter_fn))
},
None =>
unsafe {
ffi::knet_handle_enable_filter(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
None)
},
};
if res == 0 {
return Ok(());
} else {
return Err(Error::last_os_error());
}
};
Err(Error::new(ErrorKind::Other, "Rust handle not found"))
}
/// Set timer resolution
pub fn handle_set_threads_timer_res(handle: Handle, timeres: u32) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_set_threads_timer_res(handle.knet_handle as ffi::knet_handle_t, timeres)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get timer resolution
pub fn handle_get_threads_timer_res(handle: Handle) -> Result<u32>
{
let mut c_timeres: u32 = 0;
let res = unsafe {
ffi::knet_handle_get_threads_timer_res(handle.knet_handle as ffi::knet_handle_t, &mut c_timeres)
};
if res == 0 {
Ok(c_timeres)
} else {
Err(Error::last_os_error())
}
}
/// Starts traffic moving. You must call this before knet will do anything.
pub fn handle_setfwd(handle: Handle, enabled: bool) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_setfwd(handle.knet_handle as ffi::knet_handle_t,
enabled as c_uint)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Enable access control lists
pub fn handle_enable_access_lists(handle: Handle, enabled: bool) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_enable_access_lists(handle.knet_handle as ffi::knet_handle_t,
enabled as c_uint)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Set frequency that PMTUd will check for MTU changes. value in milliseconds
pub fn handle_pmtud_setfreq(handle: Handle, interval: u32) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_pmtud_setfreq(handle.knet_handle as ffi::knet_handle_t,
interval)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get frequency that PMTUd will check for MTU changes. value in milliseconds
pub fn handle_pmtud_getfreq(handle: Handle) -> Result<u32>
{
let mut c_interval = 0u32;
let res = unsafe {
ffi::knet_handle_pmtud_getfreq(handle.knet_handle as ffi::knet_handle_t,
&mut c_interval)
};
if res == 0 {
Ok(c_interval)
} else {
Err(Error::last_os_error())
}
}
/// Get the current MTU
pub fn handle_pmtud_get(handle: Handle) -> Result<u32>
{
let mut c_mtu = 0u32;
let res = unsafe {
ffi::knet_handle_pmtud_get(handle.knet_handle as ffi::knet_handle_t,
&mut c_mtu)
};
if res == 0 {
Ok(c_mtu)
} else {
Err(Error::last_os_error())
}
}
/// Set the interface MTU (this should not be necessary)
pub fn handle_pmtud_set(handle: Handle, iface_mtu: u32) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_pmtud_set(handle.knet_handle as ffi::knet_handle_t,
iface_mtu)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Enable notification of MTU changes
pub fn handle_enable_pmtud_notify(handle: Handle,
private_data: u64,
pmtud_notify_fn: Option<PmtudNotifyFn>) -> Result<()>
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(handle.knet_handle)) {
h.pmtud_notify_private_data = private_data;
h.pmtud_notify_fn = pmtud_notify_fn;
let res = match pmtud_notify_fn {
Some(_f) =>
unsafe {
ffi::knet_handle_enable_pmtud_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
Some(rust_pmtud_notify_fn))
},
None =>
unsafe {
ffi::knet_handle_enable_pmtud_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
None)
},
};
if res == 0 {
return Ok(());
} else {
return Err(Error::last_os_error());
}
}
Err(Error::new(ErrorKind::Other, "Rust handle not found"))
}
/// Configure cryptographic seetings for packets being transmitted
pub fn handle_crypto_set_config(handle: Handle, config: &CryptoConfig, config_num: u8) -> Result<()>
{
let mut crypto_cfg = ffi::knet_handle_crypto_cfg {
crypto_model: [0; 16],
crypto_cipher_type: [0; 16],
crypto_hash_type: [0; 16],
private_key: [0; 4096],
private_key_len: 0,
};
if config.private_key.len() > 4096 {
return Err(Error::new(ErrorKind::Other, "key too long"));
}
crate::string_to_bytes(&config.crypto_model, &mut crypto_cfg.crypto_model)?;
crate::string_to_bytes(&config.crypto_cipher_type, &mut crypto_cfg.crypto_cipher_type)?;
crate::string_to_bytes(&config.crypto_hash_type, &mut crypto_cfg.crypto_hash_type)?;
unsafe {
// NOTE param order is 'wrong-way round' from C
copy_nonoverlapping(config.private_key.as_ptr(), crypto_cfg.private_key.as_mut_ptr(), config.private_key.len());
}
crypto_cfg.private_key_len = config.private_key.len() as u32;
let res = unsafe {
ffi::knet_handle_crypto_set_config(handle.knet_handle as ffi::knet_handle_t,
&mut crypto_cfg,
config_num)
};
if res == 0 {
Ok(())
} else {
if res == -2 {
Err(Error::new(ErrorKind::Other, "Other cryto error"))
} else {
Err(Error::last_os_error())
}
}
}
/// Whether to allow or disallow clear-text traffic when crypto is enabled with [handle_crypto_rx_clear_traffic]
pub enum RxClearTraffic {
Allow = 0,
Disallow = 1,
}
/// Enable or disable clear-text traffic when crypto is enabled
pub fn handle_crypto_rx_clear_traffic(handle: Handle, value: RxClearTraffic) -> Result<()>
{
let c_value : u8 =
match value {
RxClearTraffic::Allow => 0,
RxClearTraffic::Disallow => 1
};
let res = unsafe {
ffi::knet_handle_crypto_rx_clear_traffic(handle.knet_handle as ffi::knet_handle_t,
c_value)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Tell knet which crypto settings to use
pub fn handle_crypto_use_config(handle: Handle, config_num: u8) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_crypto_use_config(handle.knet_handle as ffi::knet_handle_t,
config_num)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Set up packet compression
pub fn handle_compress(handle: Handle, config: &CompressConfig) -> Result<()>
{
let mut compress_cfg = ffi::knet_handle_compress_cfg {
compress_model: [0; 16],
compress_threshold : config.compress_threshold,
compress_level : config.compress_level
};
if config.compress_model.len() > 16 {
return Err(Error::new(ErrorKind::Other, "key too long"));
}
crate::string_to_bytes(&config.compress_model, &mut compress_cfg.compress_model)?;
let res = unsafe {
ffi::knet_handle_compress(handle.knet_handle as ffi::knet_handle_t,
&mut compress_cfg)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Stats for the knet handle
pub type HandleStats = ffi::knet_handle_stats;
impl HandleStats {
pub fn new() -> HandleStats
{
HandleStats {
size: 0,
tx_uncompressed_packets: 0,
tx_compressed_packets: 0,
tx_compressed_original_bytes: 0,
tx_compressed_size_bytes: 0,
tx_compress_time_ave: 0,
tx_compress_time_min: 0,
tx_compress_time_max: 0,
tx_failed_to_compress: 0,
tx_unable_to_compress: 0,
rx_compressed_packets: 0,
rx_compressed_original_bytes: 0,
rx_compressed_size_bytes: 0,
rx_compress_time_ave: 0,
rx_compress_time_min: 0,
rx_compress_time_max: 0,
rx_failed_to_decompress: 0,
tx_crypt_packets: 0,
tx_crypt_byte_overhead: 0,
tx_crypt_time_ave: 0,
tx_crypt_time_min: 0,
tx_crypt_time_max: 0,
rx_crypt_packets: 0,
rx_crypt_time_ave: 0,
rx_crypt_time_min: 0,
rx_crypt_time_max: 0,
}
}
}
impl Default for ffi::knet_handle_stats {
fn default() -> Self {
ffi::knet_handle_stats::new()
}
}
impl fmt::Display for HandleStats {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}, ", self.tx_uncompressed_packets)?;
write!(f, "{}, ", self.tx_compressed_packets)?;
write!(f, "{}, ", self.tx_compressed_original_bytes)?;
write!(f, "{}, ", self.tx_compressed_size_bytes)?;
write!(f, "{}, ", self.tx_compress_time_ave)?;
write!(f, "{}, ", self.tx_compress_time_min)?;
write!(f, "{}, ", self.tx_compress_time_max)?;
write!(f, "{}, ", self.tx_failed_to_compress)?;
write!(f, "{}, ", self.tx_unable_to_compress)?;
write!(f, "{}, ", self.rx_compressed_packets)?;
write!(f, "{}, ", self.rx_compressed_original_bytes)?;
write!(f, "{}, ", self.rx_compressed_size_bytes)?;
write!(f, "{}, ", self.rx_compress_time_ave)?;
write!(f, "{}, ", self.rx_compress_time_min)?;
write!(f, "{}, ", self.rx_compress_time_max)?;
write!(f, "{}, ", self.rx_failed_to_decompress)?;
write!(f, "{}, ", self.tx_crypt_packets)?;
write!(f, "{}, ", self.tx_crypt_byte_overhead)?;
write!(f, "{}, ", self.tx_crypt_time_ave)?;
write!(f, "{}, ", self.tx_crypt_time_min)?;
write!(f, "{}, ", self.tx_crypt_time_max)?;
write!(f, "{}, ", self.rx_crypt_packets)?;
write!(f, "{}, ", self.rx_crypt_time_ave)?;
write!(f, "{}, ", self.rx_crypt_time_min)?;
write!(f, "{}, ", self.rx_crypt_time_max)?;
Ok(())
}
}
/// Return statistics for this knet handle
pub fn handle_get_stats(handle: Handle) -> Result<HandleStats>
{
let (res, stats) = unsafe {
let mut c_stats = HandleStats::new();
let res = ffi::knet_handle_get_stats(handle.knet_handle as ffi::knet_handle_t,
&mut c_stats, size_of::<HandleStats>());
(res, c_stats)
};
if res == 0 {
Ok(stats)
} else {
Err(Error::last_os_error())
}
}
/// Tell [handle_clear_stats] whether to cleat all stats or just handle stats
pub enum ClearStats {
Handle = 1,
HandleAndLink = 2,
}
/// Clear statistics
pub fn handle_clear_stats(handle: Handle, clear_options: ClearStats) -> Result<()>
{
let c_value : i32 =
match clear_options {
ClearStats::Handle => 1,
ClearStats::HandleAndLink => 2
};
let res = unsafe {
ffi::knet_handle_clear_stats(handle.knet_handle as ffi::knet_handle_t,
c_value)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Crypto info returned from [get_crypto_list]
pub struct CryptoInfo
{
pub name: String,
pub properties: u8, // Unused
}
impl CryptoInfo
{
pub fn new(c_info: ffi::knet_crypto_info) -> CryptoInfo
{
let cstr = unsafe {CStr::from_ptr(c_info.name) };
let name = match cstr.to_str() {
Ok(s) => s.to_string(),
Err(e) => e.to_string(),
};
CryptoInfo {properties: 0,
name}
}
}
/// Get a list of valid crypto options
pub fn get_crypto_list() -> Result<Vec<CryptoInfo>>
{
let mut list_entries: usize = 256;
let mut c_list : [ffi::knet_crypto_info; 256] =
[ ffi::knet_crypto_info{name: null(), properties: 0u8, pad:[0; 256]}; 256];
let res = unsafe {
ffi::knet_get_crypto_list(&mut c_list[0],
&mut list_entries)
};
if res == 0 {
let mut retvec = Vec::<CryptoInfo>::new();
for i in c_list.iter().take(list_entries) {
retvec.push(CryptoInfo::new(*i));
}
Ok(retvec)
} else {
Err(Error::last_os_error())
}
}
/// Compressions types returned from [get_compress_list]
pub struct CompressInfo
{
pub name: String,
pub properties: u8, // Unused
}
impl CompressInfo
{
pub fn new(c_info: ffi::knet_compress_info) -> CompressInfo
{
let cstr = unsafe {CStr::from_ptr(c_info.name) };
let name = match cstr.to_str() {
Ok(s) => s.to_string(),
Err(e) => e.to_string(),
};
CompressInfo {properties: 0,
name}
}
}
/// Return a list of compression options
pub fn get_compress_list() -> Result<Vec<CompressInfo>>
{
let mut list_entries: usize = 256;
let mut c_list : [ffi::knet_compress_info; 256] =
[ ffi::knet_compress_info{name: null(), properties: 0u8, pad:[0; 256]}; 256];
let res = unsafe {
ffi::knet_get_compress_list(&mut c_list[0],
&mut list_entries)
};
if res == 0 {
let mut retvec = Vec::<CompressInfo>::new();
for i in c_list.iter().take(list_entries) {
retvec.push(CompressInfo::new(*i));
}
Ok(retvec)
} else {
Err(Error::last_os_error())
}
}
/// Enable callback when the onwire version for a node changes
pub fn handle_enable_onwire_ver_notify(handle: Handle,
private_data: u64,
onwire_notify_fn: Option<OnwireNotifyFn>) -> Result<()>
{
// This looks a bit different to the other _enable*_notify calls because knet
// calls the callback function in the API. Which results in a deadlock with our
// own mutex
if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(handle.knet_handle)) {
h.onwire_notify_private_data = private_data;
h.onwire_notify_fn = onwire_notify_fn;
} else {
return Err(Error::new(ErrorKind::Other, "Rust handle not found"));
};
let res = match onwire_notify_fn {
Some(_f) =>
unsafe {
ffi::knet_handle_enable_onwire_ver_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
Some(rust_onwire_notify_fn))
},
None =>
unsafe {
ffi::knet_handle_enable_onwire_ver_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
None)
},
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get the onsure version for a node
pub fn handle_get_onwire_ver(handle: Handle, host_id: &HostId) -> Result<(u8,u8,u8)>
{
let mut onwire_min_ver = 0u8;
let mut onwire_max_ver = 0u8;
let mut onwire_ver = 0u8;
let res = unsafe {
ffi::knet_handle_get_onwire_ver(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id,
&mut onwire_min_ver,
&mut onwire_max_ver,
&mut onwire_ver)
};
if res == 0 {
Ok((onwire_min_ver, onwire_max_ver, onwire_ver))
} else {
Err(Error::last_os_error())
}
}
/// Set the onsire version for this node
pub fn handle_set_onwire_ver(handle: Handle, onwire_ver: u8) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_set_onwire_ver(handle.knet_handle as ffi::knet_handle_t,
onwire_ver)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Set the reconnect interval.
pub fn handle_set_transport_reconnect_interval(handle: Handle, msecs: u32) -> Result<()>
{
let res = unsafe {
ffi::knet_handle_set_transport_reconnect_interval(handle.knet_handle as ffi::knet_handle_t,
msecs)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get the reconnect interval.
pub fn handle_get_transport_reconnect_interval(handle: Handle) -> Result<u32>
{
let mut msecs = 0u32;
let res = unsafe {
ffi::knet_handle_get_transport_reconnect_interval(handle.knet_handle as ffi::knet_handle_t,
&mut msecs)
};
if res == 0 {
Ok(msecs)
} else {
Err(Error::last_os_error())
}
}
/// Add a new host ID
pub fn host_add(handle: Handle, host_id: &HostId) -> Result<()>
{
let res = unsafe {
ffi::knet_host_add(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Remove a Host ID
pub fn host_remove(handle: Handle, host_id: &HostId) -> Result<()>
{
let res = unsafe {
ffi::knet_host_remove(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Set the name of a host
pub fn host_set_name(handle: Handle, host_id: &HostId, name: &str) -> Result<()>
{
let c_name = CString::new(name)?;
let res = unsafe {
ffi::knet_host_set_name(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, c_name.as_ptr())
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
const KNET_MAX_HOST_LEN:usize = 256;
const KNET_MAX_PORT_LEN:usize = 6;
/// Retrieve the name of a host given its ID
pub fn host_get_name_by_host_id(handle: Handle, host_id: &HostId) -> Result<String>
{
let mut c_name: [c_char; KNET_MAX_HOST_LEN] = [0; KNET_MAX_HOST_LEN];
let res = unsafe {
ffi::knet_host_get_name_by_host_id(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, c_name.as_mut_ptr())
};
if res == 0 {
crate::string_from_bytes(c_name.as_ptr(), KNET_MAX_HOST_LEN)
} else {
Err(Error::last_os_error())
}
}
/// Return the ID of a host given its name
pub fn host_get_id_by_host_name(handle: Handle, name: &str) -> Result<HostId>
{
let c_name = CString::new(name)?;
let mut c_host_id = 0u16;
let res = unsafe {
ffi::knet_host_get_id_by_host_name(handle.knet_handle as ffi::knet_handle_t,
c_name.as_ptr(), &mut c_host_id)
};
if res == 0 {
Ok(HostId{host_id: c_host_id})
} else {
Err(Error::last_os_error())
}
}
const KNET_MAX_HOST: usize = 65536;
/// Return a list of host IDs known to this handle
pub fn host_get_host_list(handle: Handle) -> Result<Vec<HostId>>
{
let mut c_host_ids: [u16; KNET_MAX_HOST] = [0; KNET_MAX_HOST];
let mut c_host_ids_entries: usize = 0;
let res = unsafe {
ffi::knet_host_get_host_list(handle.knet_handle as ffi::knet_handle_t,
&mut c_host_ids[0], &mut c_host_ids_entries)
};
if res == 0 {
let mut host_vec = Vec::<HostId>::new();
for i in c_host_ids.iter().take(c_host_ids_entries) {
host_vec.push(HostId {host_id: *i});
}
Ok(host_vec)
} else {
Err(Error::last_os_error())
}
}
/// Link Policies for [host_set_policy]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum LinkPolicy {
Passive,
Active,
Rr,
}
impl LinkPolicy{
pub fn new(value: u8) -> LinkPolicy
{
match value {
2 => LinkPolicy::Rr,
1 => LinkPolicy::Active,
_ => LinkPolicy::Passive,
}
}
pub fn to_u8(self: LinkPolicy) -> u8
{
match self {
LinkPolicy::Passive => 0,
LinkPolicy::Active => 1,
LinkPolicy::Rr => 2,
}
}
}
impl fmt::Display for LinkPolicy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LinkPolicy::Passive => write!(f, "Passive"),
LinkPolicy::Active => write!(f, "Active"),
LinkPolicy::Rr => write!(f, "RR"),
}
}
}
/// Set the policy for this host, this only makes sense if multiple links between hosts are configured
pub fn host_set_policy(handle: Handle, host_id: &HostId, policy: LinkPolicy) -> Result<()>
{
let c_value: u8 = policy.to_u8();
let res = unsafe {
ffi::knet_host_set_policy(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, c_value)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Return the current link policy for a node
pub fn host_get_policy(handle: Handle, host_id: &HostId) -> Result<LinkPolicy>
{
let mut c_value: u8 = 0;
let res = unsafe {
ffi::knet_host_get_policy(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, &mut c_value)
};
if res == 0 {
Ok(LinkPolicy::new(c_value))
} else {
Err(Error::last_os_error())
}
}
/// Current status of a host. remote & reachable are current not used
pub struct HostStatus
{
pub reachable: bool,
pub remote: bool,
pub external: bool,
}
impl fmt::Display for HostStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "reachable: {}, ", self.reachable)?;
write!(f, "remote: {}, ", self.remote)?;
write!(f, "external: {}", self.external)?;
Ok(())
}
}
/// Return the current status of a host
pub fn host_get_status(handle: Handle, host_id: &HostId) -> Result<HostStatus>
{
let mut c_value = ffi::knet_host_status { reachable:0, remote:0, external:0};
let res = unsafe {
ffi::knet_host_get_status(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, &mut c_value)
};
if res == 0 {
Ok(HostStatus {
reachable: crate::u8_to_bool(c_value.reachable),
remote: crate::u8_to_bool(c_value.remote),
external: crate::u8_to_bool(c_value.external)
})
} else {
Err(Error::last_os_error())
}
}
/// Enable callbacks when the status of a host changes
pub fn host_enable_status_change_notify(handle: Handle,
private_data: u64,
host_status_change_notify_fn: Option<HostStatusChangeNotifyFn>) -> Result<()>
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(handle.knet_handle)) {
h.host_status_change_notify_private_data = private_data;
h.host_status_change_notify_fn = host_status_change_notify_fn;
let res = match host_status_change_notify_fn {
Some(_f) =>
unsafe {
ffi::knet_host_enable_status_change_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
Some(rust_host_status_change_notify_fn))
},
None =>
unsafe {
ffi::knet_host_enable_status_change_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
None)
},
};
if res == 0 {
return Ok(());
} else {
return Err(Error::last_os_error());
}
}
Err(Error::new(ErrorKind::Other, "Rust handle not found"))
}
/// Transport types supported in knet
pub enum TransportId {
Loopback,
Udp,
Sctp,
}
impl TransportId {
pub fn new(id: u8) -> TransportId
{
match id {
2 => TransportId::Sctp,
1 => TransportId::Udp,
_ => TransportId::Loopback,
}
}
pub fn to_u8(self: &TransportId) -> u8
{
match self {
TransportId::Loopback => 0,
TransportId::Udp => 1,
TransportId::Sctp => 2,
}
}
pub fn to_string(self: &TransportId) -> String
{
match self {
TransportId::Udp => "UDP".to_string(),
TransportId::Sctp => "SCTP".to_string(),
TransportId::Loopback => "Loopback".to_string()
}
}
pub fn from_string(name: String) -> TransportId
{
match name.as_str() {
"UDP" => TransportId::Udp,
"SCTP" => TransportId::Sctp,
"Loopback" => TransportId::Loopback,
_ => TransportId::Loopback,
}
}
}
/// Transport info returned from [get_transport_list]
pub struct TransportInfo
{
pub name: String,
pub id: TransportId,
pub properties: u8, // currently unused
}
// Controversially implementing name_by_id and id_by_name here
impl TransportInfo
{
pub fn new(c_info: ffi::knet_transport_info) -> TransportInfo
{
let cstr = unsafe {CStr::from_ptr(c_info.name) };
let name = match cstr.to_str() {
Ok(s) => s.to_string(),
Err(e) => e.to_string(),
};
TransportInfo {properties: 0,
id: TransportId::new(c_info.id),
name}
}
}
pub fn get_transport_list() -> Result<Vec<TransportInfo>>
{
let mut list_entries: usize = 256;
let mut c_list : [ffi::knet_transport_info; 256] =
[ ffi::knet_transport_info{name: null(), id: 0u8, properties: 0u8, pad:[0; 256]}; 256];
let res = unsafe {
ffi::knet_get_transport_list(&mut c_list[0],
&mut list_entries)
};
if res == 0 {
let mut retvec = Vec::<TransportInfo>::new();
for i in c_list.iter().take(list_entries) {
retvec.push(TransportInfo::new(*i));
}
Ok(retvec)
} else {
Err(Error::last_os_error())
}
}
/// Configure a link to a host ID. dst_addr may be None for a dynamic link.
pub fn link_set_config(handle: Handle, host_id: &HostId, link_id: u8,
transport: TransportId,
src_addr: &SocketAddr, dst_addr: Option<&SocketAddr>, flags: LinkFlags) -> Result<()>
{
// Not really mut, but C is dumb
let mut c_srcaddr = make_new_sockaddr_storage(src_addr);
// dst_addr can be NULL/None if this is a dynamic link
let res = if let Some(dst) = dst_addr {
let mut c_dstaddr = make_new_sockaddr_storage(dst);
unsafe {
ffi::knet_link_set_config(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
transport.to_u8(),
&mut c_srcaddr,
&mut c_dstaddr,
flags.bits)
}
} else {
unsafe {
ffi::knet_link_set_config(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
transport.to_u8(),
&mut c_srcaddr,
null_mut(),
flags.bits)
}
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Return a link's configuration
pub fn link_get_config(handle: Handle, host_id: &HostId, link_id: u8) ->
Result<(TransportId, Option<SocketAddr>, Option<SocketAddr>, LinkFlags)>
{
let mut c_srcaddr = OsSocketAddr::new();
let mut c_dstaddr = OsSocketAddr::new();
let mut c_transport = 0u8;
let mut c_flags = 0u64;
let mut c_dynamic = 0u8;
let res = unsafe {
ffi::knet_link_get_config(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
&mut c_transport,
c_srcaddr.as_mut_ptr() as *mut ffi::sockaddr_storage,
c_dstaddr.as_mut_ptr() as *mut ffi::sockaddr_storage,
&mut c_dynamic,
&mut c_flags)
};
if res == 0 {
let r_transport = TransportId::new(c_transport);
Ok((r_transport, c_srcaddr.into(), c_dstaddr.into(), LinkFlags{bits:c_flags}))
} else {
Err(Error::last_os_error())
}
}
/// Clear a link configuration.
pub fn link_clear_config(handle: Handle, host_id: &HostId, link_id: u8) -> Result<()>
{
let res = unsafe {
ffi::knet_link_clear_config(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Type of ACL
pub enum AclAcceptReject
{
Accept,
Reject,
}
impl AclAcceptReject {
pub fn new(ar: u32) -> AclAcceptReject
{
match ar {
ffi::CHECK_ACCEPT => AclAcceptReject::Accept,
ffi::CHECK_REJECT => AclAcceptReject::Reject,
_ => AclAcceptReject::Reject,
}
}
pub fn to_u32(self: &AclAcceptReject) -> u32
{
match self {
AclAcceptReject::Accept => ffi::CHECK_ACCEPT,
AclAcceptReject::Reject => ffi::CHECK_REJECT,
}
}
}
/// What the ACL should check
pub enum AclCheckType
{
Address,
Mask,
Range,
}
impl AclCheckType {
pub fn new(ct: u32) -> AclCheckType
{
match ct {
ffi::CHECK_TYPE_ADDRESS => AclCheckType::Address,
ffi::CHECK_TYPE_MASK => AclCheckType::Mask,
ffi::CHECK_TYPE_RANGE => AclCheckType::Range,
_ => AclCheckType::Address,
}
}
pub fn to_u32(self: &AclCheckType) -> u32
{
match self {
AclCheckType::Address => ffi::CHECK_TYPE_ADDRESS,
AclCheckType::Mask => ffi::CHECK_TYPE_MASK,
AclCheckType::Range => ffi::CHECK_TYPE_RANGE,
}
}
}
// We need to have a zeroed-out stackaddr storage to pass to the ACL APIs
// as knet compares the whole sockaddr_storage when using knet_rm_acl()
fn make_new_sockaddr_storage(ss: &SocketAddr) -> ffi::sockaddr_storage
{
// A blank one
-#[cfg(any(target_os="freebsd"))]
+#[cfg(target_os="freebsd")]
let mut new_ss = ffi::sockaddr_storage {
ss_family: 0,
ss_len: 0,
__ss_pad1: [0; 6],
__ss_align: 0,
__ss_pad2: [0; 112],
};
-#[cfg(any(target_os="linux"))]
+#[cfg(target_os="linux")]
let mut new_ss = ffi::sockaddr_storage {
ss_family: 0,
__ss_padding: [0; 118],
__ss_align: 0,
};
let p_new_ss : *mut ffi::sockaddr_storage = &mut new_ss;
// Rust only fills in what it thinks is necessary
let c_ss : OsSocketAddr = (*ss).into();
// Copy it
unsafe {
// Only copy as much as is in the OsSocketAddr
copy_nonoverlapping(c_ss.as_ptr(),
p_new_ss as *mut libc::sockaddr,
1);
}
new_ss
}
/// Add an ACL to a link, adds the ACL to the end of the list.
pub fn link_add_acl(handle: Handle, host_id: &HostId, link_id: u8,
ss1: &SocketAddr, ss2: &SocketAddr,
check_type: AclCheckType, acceptreject: AclAcceptReject) -> Result<()>
{
// Not really mut, but C is dumb
let mut c_ss1 = make_new_sockaddr_storage(ss1);
let mut c_ss2 = make_new_sockaddr_storage(ss2);
let res = unsafe {
ffi::knet_link_add_acl(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
&mut c_ss1,
&mut c_ss2,
check_type.to_u32(), acceptreject.to_u32())
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Insert an ACL anywhere in the ACL list for this host/link
pub fn link_insert_acl(handle: Handle, host_id: &HostId, link_id: u8,
index: i32,
ss1: &SocketAddr, ss2: &SocketAddr,
check_type: AclCheckType, acceptreject: AclAcceptReject) -> Result<()>
{
// Not really mut, but C is dumb
let mut c_ss1 = make_new_sockaddr_storage(ss1);
let mut c_ss2 = make_new_sockaddr_storage(ss2);
let res = unsafe {
ffi::knet_link_insert_acl(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
index,
&mut c_ss1,
&mut c_ss2,
check_type.to_u32(), acceptreject.to_u32())
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Remove an ACL for this host/link
pub fn link_rm_acl(handle: Handle, host_id: &HostId, link_id: u8,
ss1: &SocketAddr, ss2: &SocketAddr,
check_type: AclCheckType, acceptreject: AclAcceptReject) -> Result<()>
{
// Not really mut, but C is dumb
let mut c_ss1 = make_new_sockaddr_storage(ss1);
let mut c_ss2 = make_new_sockaddr_storage(ss2);
let res = unsafe {
ffi::knet_link_rm_acl(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
&mut c_ss1,
&mut c_ss2,
check_type.to_u32(), acceptreject.to_u32())
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Clear out all ACLs from this host/link
pub fn link_clear_acl(handle: Handle, host_id: &HostId, link_id: u8) -> Result<()>
{
let res = unsafe {
ffi::knet_link_clear_acl(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Enable/disable a link (you still need to call [handle_setfwd] for traffic to flow
pub fn link_set_enable(handle: Handle, host_id: &HostId, link_id: u8, enable: bool) -> Result<()>
{
let res = unsafe {
ffi::knet_link_set_enable(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id, enable as u32)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get the 'enabled' status for a link
pub fn link_get_enable(handle: Handle, host_id: &HostId, link_id: u8) -> Result<bool>
{
let mut c_enable = 0u32;
let res = unsafe {
ffi::knet_link_get_enable(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id, &mut c_enable)
};
if res == 0 {
Ok(crate::u32_to_bool(c_enable))
} else {
Err(Error::last_os_error())
}
}
/// Set the ping timers for a link
pub fn link_set_ping_timers(handle: Handle, host_id: &HostId, link_id: u8,
interval: i64, timeout: i64, precision: u32) -> Result<()>
{
let res = unsafe {
ffi::knet_link_set_ping_timers(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
interval, timeout, precision)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get the ping timers for a link
pub fn link_get_ping_timers(handle: Handle, host_id: &HostId, link_id: u8) -> Result<(i64, i64, u32)>
{
let mut c_interval : ffi::time_t = 0;
let mut c_timeout : ffi::time_t = 0;
let mut c_precision = 0u32;
let res = unsafe {
ffi::knet_link_get_ping_timers(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
&mut c_interval, &mut c_timeout, &mut c_precision)
};
if res == 0 {
Ok((c_interval, c_timeout, c_precision))
} else {
Err(Error::last_os_error())
}
}
/// Set the pong count for a link
pub fn link_set_pong_count(handle: Handle, host_id: &HostId, link_id: u8,
pong_count: u8) -> Result<()>
{
let res = unsafe {
ffi::knet_link_set_pong_count(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
pong_count)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get the pong count for a link
pub fn link_get_pong_count(handle: Handle, host_id: &HostId, link_id: u8) -> Result<u8>
{
let mut c_pong_count = 0u8;
let res = unsafe {
ffi::knet_link_get_pong_count(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
&mut c_pong_count)
};
if res == 0 {
Ok(c_pong_count)
} else {
Err(Error::last_os_error())
}
}
/// Set the link priority (only useful with multiple links to a node)
pub fn link_set_priority(handle: Handle, host_id: &HostId, link_id: u8,
priority: u8) -> Result<()>
{
let res = unsafe {
ffi::knet_link_set_priority(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
priority)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get the link priority
pub fn link_get_priority(handle: Handle, host_id: &HostId, link_id: u8) -> Result<u8>
{
let mut c_priority = 0u8;
let res = unsafe {
ffi::knet_link_get_priority(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
&mut c_priority)
};
if res == 0 {
Ok(c_priority)
} else {
Err(Error::last_os_error())
}
}
const KNET_MAX_LINK: usize = 8;
/// Get a list of links for this host
pub fn link_get_link_list(handle: Handle, host_id: &HostId) -> Result<Vec<u8>>
{
let mut c_link_ids: [u8; KNET_MAX_LINK] = [0; KNET_MAX_LINK];
let mut c_link_ids_entries: usize = 0;
let res = unsafe {
ffi::knet_link_get_link_list(handle.knet_handle as ffi::knet_handle_t, host_id.host_id,
&mut c_link_ids[0], &mut c_link_ids_entries)
};
if res == 0 {
let mut link_vec = Vec::<u8>::new();
for i in c_link_ids.iter().take(c_link_ids_entries) {
link_vec.push(*i);
}
Ok(link_vec)
} else {
Err(Error::last_os_error())
}
}
/// Enable callbacks when a link status changes
pub fn link_enable_status_change_notify(handle: Handle,
private_data: u64,
link_status_change_notify_fn: Option<LinkStatusChangeNotifyFn>) -> Result<()>
{
if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(handle.knet_handle)) {
h.link_status_change_notify_private_data = private_data;
h.link_status_change_notify_fn = link_status_change_notify_fn;
let res = match link_status_change_notify_fn {
Some(_f) =>
unsafe {
ffi::knet_link_enable_status_change_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
Some(rust_link_status_change_notify_fn))
},
None =>
unsafe {
ffi::knet_link_enable_status_change_notify(handle.knet_handle as ffi::knet_handle_t,
handle.knet_handle as *mut c_void,
None)
},
};
if res == 0 {
return Ok(());
} else {
return Err(Error::last_os_error());
}
}
Err(Error::new(ErrorKind::Other, "Rust handle not found"))
}
/// Link stats
pub struct LinkStats {
pub tx_data_packets: u64,
pub rx_data_packets: u64,
pub tx_data_bytes: u64,
pub rx_data_bytes: u64,
pub rx_ping_packets: u64,
pub tx_ping_packets: u64,
pub rx_ping_bytes: u64,
pub tx_ping_bytes: u64,
pub rx_pong_packets: u64,
pub tx_pong_packets: u64,
pub rx_pong_bytes: u64,
pub tx_pong_bytes: u64,
pub rx_pmtu_packets: u64,
pub tx_pmtu_packets: u64,
pub rx_pmtu_bytes: u64,
pub tx_pmtu_bytes: u64,
pub tx_total_packets: u64,
pub rx_total_packets: u64,
pub tx_total_bytes: u64,
pub rx_total_bytes: u64,
pub tx_total_errors: u64,
pub tx_total_retries: u64,
pub tx_pmtu_errors: u32,
pub tx_pmtu_retries: u32,
pub tx_ping_errors: u32,
pub tx_ping_retries: u32,
pub tx_pong_errors: u32,
pub tx_pong_retries: u32,
pub tx_data_errors: u32,
pub tx_data_retries: u32,
pub latency_min: u32,
pub latency_max: u32,
pub latency_ave: u32,
pub latency_samples: u32,
pub down_count: u32,
pub up_count: u32,
pub last_up_times: Vec<SystemTime>,
pub last_down_times: Vec<SystemTime>,
}
// Quick & Dirty printing
impl fmt::Display for LinkStats {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}, ", self.tx_data_packets)?;
write!(f, "{}, ", self.rx_data_packets)?;
write!(f, "{}, ", self.tx_data_bytes)?;
write!(f, "{}, ", self.rx_data_bytes)?;
write!(f, "{}, ", self.rx_ping_packets)?;
write!(f, "{}, ", self.tx_ping_packets)?;
write!(f, "{}, ", self.rx_ping_bytes)?;
write!(f, "{}, ", self.tx_ping_bytes)?;
write!(f, "{}, ", self.rx_pong_packets)?;
write!(f, "{}, ", self.tx_pong_packets)?;
write!(f, "{}, ", self.rx_pong_bytes)?;
write!(f, "{}, ", self.tx_pong_bytes)?;
write!(f, "{}, ", self.rx_pmtu_packets)?;
write!(f, "{}, ", self.tx_pmtu_packets)?;
write!(f, "{}, ", self.rx_pmtu_bytes)?;
write!(f, "{}, ", self.tx_pmtu_bytes)?;
write!(f, "{}, ", self.tx_total_packets)?;
write!(f, "{}, ", self.rx_total_packets)?;
write!(f, "{}, ", self.tx_total_bytes)?;
write!(f, "{}, ", self.rx_total_bytes)?;
write!(f, "{}, ", self.tx_total_errors)?;
write!(f, "{}, ", self.tx_total_retries)?;
write!(f, "{}, ", self.tx_pmtu_errors)?;
write!(f, "{}, ", self.tx_pmtu_retries)?;
write!(f, "{}, ", self.tx_ping_errors)?;
write!(f, "{}, ", self.tx_ping_retries)?;
write!(f, "{}, ", self.tx_pong_errors)?;
write!(f, "{}, ", self.tx_pong_retries)?;
write!(f, "{}, ", self.tx_data_errors)?;
write!(f, "{}, ", self.tx_data_retries)?;
write!(f, "{}, ", self.latency_min)?;
write!(f, "{}, ", self.latency_max)?;
write!(f, "{}, ", self.latency_ave)?;
write!(f, "{}, ", self.latency_samples)?;
write!(f, "{}, ", self.down_count)?;
write!(f, "{}, ", self.up_count)?;
write!(f, "Last up times: ")?;
// There's no sensible print for SystemTime in the std library
// and I don't want to add dependancies here for printing as it
// mostly going to be the client's responsibility, so use the Debug option
for i in &self.last_up_times {
write!(f, "{i:?}")?;
}
write!(f, " Last down times: ")?;
for i in &self.last_down_times {
write!(f, "{i:?}")?;
}
Ok(())
}
}
// I wish this all wasn't necessary!
impl ffi::knet_link_stats {
pub fn new() -> ffi::knet_link_stats {
ffi::knet_link_stats {
tx_data_packets: 0,
rx_data_packets: 0,
tx_data_bytes: 0,
rx_data_bytes: 0,
rx_ping_packets: 0,
tx_ping_packets: 0,
rx_ping_bytes: 0,
tx_ping_bytes: 0,
rx_pong_packets: 0,
tx_pong_packets: 0,
rx_pong_bytes: 0,
tx_pong_bytes: 0,
rx_pmtu_packets: 0,
tx_pmtu_packets: 0,
rx_pmtu_bytes: 0,
tx_pmtu_bytes: 0,
tx_total_packets: 0,
rx_total_packets: 0,
tx_total_bytes: 0,
rx_total_bytes: 0,
tx_total_errors: 0,
tx_total_retries: 0,
tx_pmtu_errors: 0,
tx_pmtu_retries: 0,
tx_ping_errors: 0,
tx_ping_retries: 0,
tx_pong_errors: 0,
tx_pong_retries: 0,
tx_data_errors: 0,
tx_data_retries: 0,
latency_min: 0,
latency_max: 0,
latency_ave: 0,
latency_samples: 0,
down_count: 0,
up_count: 0,
last_up_times: [0; 16],
last_down_times: [0; 16],
last_up_time_index: 0,
last_down_time_index: 0,
}
}
}
impl Default for ffi::knet_link_stats {
fn default() -> Self {
ffi::knet_link_stats::new()
}
}
impl ffi::knet_link_status {
pub fn new()-> ffi::knet_link_status
{
ffi::knet_link_status {
size: 0,
src_ipaddr : [0; KNET_MAX_HOST_LEN],
dst_ipaddr : [0; KNET_MAX_HOST_LEN],
src_port : [0; KNET_MAX_PORT_LEN],
dst_port : [0; KNET_MAX_PORT_LEN],
enabled: 0,
connected: 0,
dynconnected: 0,
pong_last: ffi::timespec{ tv_sec: 0, tv_nsec: 0},
mtu: 0,
proto_overhead: 0,
stats: ffi::knet_link_stats::new(),
}
}
}
impl Default for ffi::knet_link_status {
fn default() -> Self {
ffi::knet_link_status::new()
}
}
/// Link status (includes a [LinkStats])
pub struct LinkStatus
{
pub src_ipaddr: String,
pub dst_ipaddr: String,
pub src_port: String,
pub dst_port: String,
pub enabled: bool,
pub connected: bool,
pub dynconnected: bool,
pub pong_last: SystemTime,
pub mtu: u32,
pub proto_overhead: u32,
pub stats: LinkStats,
}
impl LinkStatus {
pub fn new(c_stats: ffi::knet_link_status) -> LinkStatus
{
LinkStatus {
src_ipaddr : crate::string_from_bytes_safe(c_stats.src_ipaddr.as_ptr(), KNET_MAX_HOST_LEN),
src_port : crate::string_from_bytes_safe(c_stats.src_port.as_ptr(), KNET_MAX_HOST_LEN),
dst_ipaddr : crate::string_from_bytes_safe(c_stats.dst_ipaddr.as_ptr(), KNET_MAX_HOST_LEN),
dst_port : crate::string_from_bytes_safe(c_stats.dst_port.as_ptr(), KNET_MAX_HOST_LEN),
enabled : crate::u8_to_bool(c_stats.enabled),
connected : crate::u8_to_bool(c_stats.connected),
dynconnected : crate::u8_to_bool(c_stats.dynconnected),
pong_last : systemtime_from_timespec(c_stats.pong_last),
mtu : c_stats.mtu,
proto_overhead : c_stats.proto_overhead,
stats : LinkStats::new(c_stats.stats),
}
}
}
impl fmt::Display for LinkStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "src_ip_addr: {}:{}, ", self.src_ipaddr, self.src_port)?;
write!(f, "dst_ip_addr: {}:{}, ", self.dst_ipaddr, self.src_port)?;
write!(f, "enabled: {}, connected: {}, mtu: {}, overhead: {}, ",
self.enabled, self.connected, self.mtu, self.proto_overhead)?;
write!(f, "stats: {}", self.stats)?;
Ok(())
}
}
fn systemtime_from_time_t(t: u64) -> SystemTime
{
SystemTime::UNIX_EPOCH+Duration::from_secs(t)
}
fn systemtime_from_timespec(t: ffi::timespec) -> SystemTime
{
SystemTime::UNIX_EPOCH+Duration::from_secs(t.tv_sec as u64)
+Duration::from_nanos(t.tv_nsec as u64) // TODO may panic??
}
fn copy_circular_buffer_of_link_events(num: usize, times: &[ffi::time_t]) -> Vec<SystemTime>
{
let mut times_vec = Vec::<SystemTime>::new();
for index in (0 .. num).rev() {
if times[index] == 0 {
break
}
times_vec.push(systemtime_from_time_t(times[index] as u64)); // TODO may panic??
}
for index in (num+1 .. MAX_LINK_EVENTS).rev() {
if times[index] == 0 {
break;
}
times_vec.push(systemtime_from_time_t(times[index] as u64)); // TODO may panic??
}
times_vec
}
const MAX_LINK_EVENTS: usize = 16;
impl LinkStats {
pub fn new(cstats: ffi::knet_link_stats) -> LinkStats
{
let up_times = copy_circular_buffer_of_link_events(cstats.last_up_time_index as usize,
&cstats.last_up_times);
let down_times = copy_circular_buffer_of_link_events(cstats.last_down_time_index as usize,
&cstats.last_down_times);
LinkStats {
tx_data_packets: cstats.tx_data_packets,
rx_data_packets: cstats.rx_data_packets,
tx_data_bytes: cstats.tx_data_bytes,
rx_data_bytes: cstats.rx_data_bytes,
rx_ping_packets: cstats.rx_ping_packets,
tx_ping_packets: cstats.tx_ping_packets,
rx_ping_bytes: cstats.rx_ping_bytes,
tx_ping_bytes: cstats.tx_ping_bytes,
rx_pong_packets: cstats.rx_pong_packets,
tx_pong_packets: cstats.tx_pong_packets,
rx_pong_bytes: cstats.rx_pong_bytes,
tx_pong_bytes: cstats.tx_pong_bytes,
rx_pmtu_packets: cstats.rx_pmtu_packets,
tx_pmtu_packets: cstats.tx_pmtu_packets,
rx_pmtu_bytes: cstats.rx_pmtu_bytes,
tx_pmtu_bytes: cstats.tx_pmtu_bytes,
tx_total_packets: cstats.tx_total_packets,
rx_total_packets: cstats.rx_total_packets,
tx_total_bytes: cstats.tx_total_bytes,
rx_total_bytes: cstats.rx_total_bytes,
tx_total_errors: cstats.tx_total_errors,
tx_total_retries: cstats.tx_total_retries,
tx_pmtu_errors: cstats.tx_pmtu_errors,
tx_pmtu_retries: cstats.tx_pmtu_retries,
tx_ping_errors: cstats.tx_ping_errors,
tx_ping_retries: cstats.tx_ping_retries,
tx_pong_errors: cstats.tx_pong_errors,
tx_pong_retries: cstats.tx_pong_retries,
tx_data_errors: cstats.tx_data_errors,
tx_data_retries: cstats.tx_data_retries,
latency_min: cstats.latency_min,
latency_max: cstats.latency_max,
latency_ave: cstats.latency_ave,
latency_samples: cstats.latency_samples,
down_count: cstats.down_count,
up_count: cstats.up_count,
last_up_times: up_times,
last_down_times: down_times,
}
}
}
/// Get the status (and stats) of a link
pub fn link_get_status(handle: Handle, host_id: &HostId, link_id: u8) -> Result<LinkStatus>
{
let (res, stats) = unsafe {
let mut c_stats : ffi::knet_link_status = ffi::knet_link_status::new();
let res = ffi::knet_link_get_status(handle.knet_handle as ffi::knet_handle_t,
host_id.host_id, link_id,
&mut c_stats, size_of::<ffi::knet_link_status>());
(res, c_stats)
};
if res == 0 {
let r_status = LinkStatus::new(stats);
Ok(r_status)
} else {
Err(Error::last_os_error())
}
}
/// Get the logging subsystem ID given its name
pub fn log_get_subsystem_id(name: &str) -> Result<u8>
{
let c_name = CString::new(name)?;
let res = unsafe {
ffi::knet_log_get_subsystem_id(c_name.as_ptr())
};
Ok(res)
}
/// Get the logging subsystem name given its ID
pub fn log_get_subsystem_name(id: u8) -> Result<String>
{
let res = unsafe {
ffi::knet_log_get_subsystem_name(id)
};
crate::string_from_bytes(res, 256)
}
/// Get the name of a logging level
pub fn log_get_loglevel_id(name: &str) -> Result<u8>
{
let c_name = CString::new(name)?;
let res = unsafe {
ffi::knet_log_get_loglevel_id(c_name.as_ptr())
};
Ok(res)
}
/// Get the ID of a logging level, given its name
pub fn log_get_loglevel_name(id: u8) -> Result<String>
{
let res = unsafe {
ffi::knet_log_get_loglevel_name(id)
};
crate::string_from_bytes(res, 256)
}
/// Logging levels
pub enum LogLevel {
Err,
Warn,
Info,
Debug,
Trace,
}
impl LogLevel {
pub fn new(level: u8) -> LogLevel {
match level {
0 => LogLevel::Err,
1 => LogLevel::Warn,
2 => LogLevel::Info,
3 => LogLevel::Debug,
_ => LogLevel::Trace // 4=Trace, but default anything to it too
}
}
pub fn to_u8(self: &LogLevel) -> u8
{
match self {
LogLevel::Err => 0,
LogLevel::Warn => 1,
LogLevel::Info => 2,
LogLevel::Debug => 3,
LogLevel::Trace => 4,
}
}
}
impl fmt::Display for LogLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LogLevel::Err => write!(f, "Err"),
LogLevel::Warn => write!(f, "Warn"),
LogLevel::Info => write!(f, "Info"),
LogLevel::Debug => write!(f, "Debug"),
LogLevel::Trace => write!(f, "Trace"),
}
}
}
/// Subsystems known to the knet logger
pub enum SubSystem
{
Common,
Handle,
Host,
Listener,
Link,
Transport,
Crypto,
Compress,
Filter,
Dstcache,
Heartbeat,
Pmtud,
Tx,
Rx,
TranspBase,
TranspLoopback,
TranspUdp,
TranspSctp,
NssCrypto,
OpensslCrypto,
Zlibcomp,
Lz4comp,
Lz4hccomp,
Lzo2comp,
Lzmacomp,
Bzip2comp,
Zstdcomp,
Unknown,
}
impl SubSystem {
pub fn to_u8(self: &SubSystem) -> u8
{
match self {
SubSystem::Common => ffi::KNET_SUB_COMMON,
SubSystem::Handle => ffi::KNET_SUB_HANDLE,
SubSystem::Host => ffi::KNET_SUB_HOST,
SubSystem::Listener => ffi::KNET_SUB_LISTENER,
SubSystem::Link => ffi::KNET_SUB_LINK,
SubSystem::Transport => ffi::KNET_SUB_TRANSPORT,
SubSystem::Crypto => ffi::KNET_SUB_CRYPTO,
SubSystem::Compress => ffi::KNET_SUB_COMPRESS,
SubSystem::Filter => ffi::KNET_SUB_FILTER,
SubSystem::Dstcache => ffi::KNET_SUB_DSTCACHE,
SubSystem::Heartbeat => ffi::KNET_SUB_HEARTBEAT,
SubSystem::Pmtud => ffi::KNET_SUB_PMTUD,
SubSystem::Tx => ffi::KNET_SUB_TX,
SubSystem::Rx => ffi::KNET_SUB_RX,
SubSystem::TranspBase => ffi::KNET_SUB_TRANSP_BASE,
SubSystem::TranspLoopback => ffi::KNET_SUB_TRANSP_LOOPBACK,
SubSystem::TranspUdp => ffi::KNET_SUB_TRANSP_UDP,
SubSystem::TranspSctp => ffi::KNET_SUB_TRANSP_SCTP,
SubSystem::NssCrypto => ffi::KNET_SUB_NSSCRYPTO,
SubSystem::OpensslCrypto => ffi::KNET_SUB_OPENSSLCRYPTO,
SubSystem::Zlibcomp => ffi::KNET_SUB_ZLIBCOMP,
SubSystem::Lz4comp => ffi::KNET_SUB_LZ4COMP,
SubSystem::Lz4hccomp => ffi::KNET_SUB_LZ4HCCOMP,
SubSystem::Lzo2comp => ffi::KNET_SUB_LZO2COMP,
SubSystem::Lzmacomp => ffi::KNET_SUB_LZMACOMP,
SubSystem::Bzip2comp => ffi::KNET_SUB_BZIP2COMP,
SubSystem::Zstdcomp => ffi::KNET_SUB_ZSTDCOMP,
SubSystem::Unknown => ffi::KNET_SUB_UNKNOWN,
}
}
pub fn new(subsys: u8) -> SubSystem
{
match subsys {
1 => SubSystem::Unknown,
2 => SubSystem::Unknown,
_ => SubSystem::Unknown,
}
}
}
/// Set the current logging level
pub fn log_set_loglevel(handle: Handle, subsystem: SubSystem, level: LogLevel) -> Result<()>
{
let c_level = level.to_u8();
let c_subsys = subsystem.to_u8();
let res = unsafe {
ffi::knet_log_set_loglevel(handle.knet_handle as ffi::knet_handle_t,
c_subsys, c_level)
};
if res == 0 {
Ok(())
} else {
Err(Error::last_os_error())
}
}
/// Get the current logging level
pub fn log_get_loglevel(handle: Handle, subsystem: SubSystem) -> Result<LogLevel>
{
let mut c_level:u8 = 0;
let c_subsys = subsystem.to_u8();
let res = unsafe {
ffi::knet_log_get_loglevel(handle.knet_handle as ffi::knet_handle_t,
c_subsys, &mut c_level)
};
if res == 0 {
Ok(LogLevel::new(c_level))
} else {
Err(Error::last_os_error())
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Feb 26, 12:49 PM (20 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1465362
Default Alt Text
(69 KB)

Event Timeline