Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3154396
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
69 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rK kronosnet
Attached
Detach File
Event Timeline
Log In to Comment