Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/libknet/bindings/rust/src/knet_bindings.rs b/libknet/bindings/rust/src/knet_bindings.rs
index 8878cb7b..01262186 100644
--- a/libknet/bindings/rust/src/knet_bindings.rs
+++ b/libknet/bindings/rust/src/knet_bindings.rs
@@ -1,2556 +1,2556 @@
// 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);
+ 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"))]
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"))]
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, "{i:?}")?;
}
write!(f, " Last down times: ")?;
for i in &self.last_down_times {
- write!(f, "{:?}", i)?;
+ 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,
}
impl LogLevel {
pub fn new(level: u8) -> LogLevel {
match level {
0 => LogLevel::Err,
1 => LogLevel::Warn,
2 => LogLevel::Info,
_ => LogLevel::Debug, // 3=Debug, 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,
}
}
}
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"),
}
}
}
/// 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())
}
}
diff --git a/libknet/bindings/rust/tests/src/bin/knet-test.rs b/libknet/bindings/rust/tests/src/bin/knet-test.rs
index c5d1a6c1..0158e7ce 100644
--- a/libknet/bindings/rust/tests/src/bin/knet-test.rs
+++ b/libknet/bindings/rust/tests/src/bin/knet-test.rs
@@ -1,974 +1,971 @@
// Testing the Knet Rust APIs
//
// Copyright (C) 2021-2023 Red Hat, Inc.
//
// All rights reserved.
//
// Author: Christine Caulfield (ccaulfi@redhat.com)
//
use knet_bindings::knet_bindings as knet;
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
use std::thread::spawn;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::channel;
use std::io::{Result, ErrorKind, Error};
use std::{thread, time};
use std::env;
const CHANNEL: i8 = 1;
// Dirty C function to set the plugin path for testing (only)
extern {
fn set_plugin_path(knet_h: knet::Handle);
}
fn is_memcheck() -> bool
{
match env::var("KNETMEMCHECK") {
Ok(s) => {
s == "yes"
}
Err(_) => false
}
}
// Probably this will never happen, but just-in-case
fn is_helgrind() -> bool
{
match env::var("KNETHELGRIND") {
Ok(s) => {
s == "yes"
}
Err(_) => false
}
}
fn get_scaled_tmo(millis: u64) -> time::Duration
{
if is_memcheck() || is_helgrind() {
println!("Running under valgrind, increasing timer from {} to {}", millis, millis*16);
time::Duration::from_millis(millis * 16)
} else {
time::Duration::from_millis(millis)
}
}
// Callbacks
fn sock_notify_fn(private_data: u64,
datafd: i32,
channel: i8,
txrx: knet::TxRx,
_res: Result<()>)
{
- println!("sock notify called for host {}, datafd: {}, channel: {}, {}",
- private_data, datafd, channel, txrx);
+ println!("sock notify called for host {private_data}, datafd: {datafd}, channel: {channel}, {txrx}");
}
fn link_notify_fn(private_data: u64,
host_id: knet::HostId,
link_id: u8,
connected: bool,
_remote: bool,
_external: bool)
{
println!("link status notify called ({}) for host {}, linkid: {}, connected: {}",
private_data, host_id.to_u16(), link_id, connected);
}
fn host_notify_fn(private_data: u64,
host_id: knet::HostId,
connected: bool,
_remote: bool,
_external: bool)
{
println!("host status notify called ({}) for host {}, connected: {}",
private_data, host_id.to_u16(), connected);
}
fn pmtud_fn(private_data: u64, data_mtu: u32) {
- println!("PMTUD notify: host {}, MTU:{} ", private_data, data_mtu);
+ println!("PMTUD notify: host {private_data}, MTU:{data_mtu} ");
}
fn onwire_fn(private_data: u64,
onwire_min_ver: u8,
onwire_max_ver: u8,
onwire_ver: u8) {
- println!("Onwire ver notify for {} : {}/{}/{}", private_data, onwire_min_ver, onwire_max_ver, onwire_ver);
+ println!("Onwire ver notify for {private_data} : {onwire_min_ver}/{onwire_max_ver}/{onwire_ver}");
}
fn filter_fn(private_data: u64,
_outdata: &[u8],
txrx: knet::TxRx,
this_host_id: knet::HostId,
src_host_id: knet::HostId,
channel: &mut i8,
dst_host_ids: &mut Vec<knet::HostId>) -> knet::FilterDecision
{
- println!("Filter ({}) called {} to {} from {}, channel: {}",
- private_data, txrx, this_host_id, src_host_id, channel);
+ println!("Filter ({private_data}) called {txrx} to {this_host_id} from {src_host_id}, channel: {channel}");
let dst: u16 = (private_data & 0xFFFF) as u16;
match txrx {
knet::TxRx::Tx => {
dst_host_ids.push(knet::HostId::new(3-dst));
knet::FilterDecision::Unicast
}
knet::TxRx::Rx => {
dst_host_ids.push(this_host_id);
knet::FilterDecision::Unicast
}
}
}
fn logging_thread(recvr: Receiver<knet::LogMsg>)
{
for i in &recvr {
eprintln!("KNET: {}", i.msg);
}
eprintln!("Logging thread finished");
}
fn setup_node(our_hostid: &knet::HostId, other_hostid: &knet::HostId, name: &str) -> Result<knet::Handle>
{
let (log_sender, log_receiver) = channel::<knet::LogMsg>();
spawn(move || logging_thread(log_receiver));
let knet_handle = match knet::handle_new(our_hostid, Some(log_sender),
knet::LogLevel::Debug, knet::HandleFlags::NONE) {
Ok(h) => h,
Err(e) => {
- println!("Error from handle_new: {}", e);
+ println!("Error from handle_new: {e}");
return Err(e);
}
};
// Make sure we use the build-tree plugins if LD_LIBRRAY_PATH points to them
unsafe {
set_plugin_path(knet_handle);
}
if let Err(e) = knet::host_add(knet_handle, other_hostid) {
- println!("Error from host_add: {}", e);
+ println!("Error from host_add: {e}");
return Err(e);
}
if let Err(e) = knet::host_set_name(knet_handle, other_hostid, name) {
- println!("Error from host_set_name: {}", e);
+ println!("Error from host_set_name: {e}");
return Err(e);
}
Ok(knet_handle)
}
// Called by the ACL tests to get a free port for a dynamic link
fn setup_dynamic_link(handle: knet::Handle, hostid: &knet::HostId, link: u8,
lowest_port: u16) -> Result<()>
{
let mut src_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);
for p in lowest_port..=65535 {
src_addr.set_port(p);
if let Err(e) = knet::link_set_config(handle, hostid, link,
knet::TransportId::Udp,
&src_addr,
None,
knet::LinkFlags::NONE) {
if let Some(os_err) = e.raw_os_error() {
if os_err != libc::EADDRINUSE {
- println!("Error from link_set_config(dyn): {}", e);
+ println!("Error from link_set_config(dyn): {e}");
return Err(e);
}
// In use - try the next port number
}
} else {
- println!("Dynamic link - Using port {}", p);
+ println!("Dynamic link - Using port {p}");
return Ok(())
}
}
Err(Error::new(ErrorKind::Other, "No ports available"))
}
// This is the bit that configures two links on two handles that talk to each other
// while also making sure they don't clash with anything else on the system
fn setup_links(handle1: knet::Handle, hostid1: &knet::HostId,
handle2: knet::Handle, hostid2: &knet::HostId) -> Result<u16>
{
let mut src_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);
let mut dst_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);
for p in 1025..=65534 {
src_addr.set_port(p);
dst_addr.set_port(p+1);
if let Err(e) = knet::link_set_config(handle1, hostid2, 0,
knet::TransportId::Udp,
&src_addr,
Some(&dst_addr),
knet::LinkFlags::NONE) {
if let Some(os_err) = e.raw_os_error() {
if os_err != libc::EADDRINUSE {
- println!("Error from link_set_config(1): {}", e);
+ println!("Error from link_set_config(1): {e}");
return Err(e);
}
// In use - try the next port number
} else {
return Err(Error::new(ErrorKind::Other, "Error returned from link_set_config(1) was not an os_error"));
}
} else {
// Now try the other handle
if let Err(e) = knet::link_set_config(handle2, hostid1, 0,
knet::TransportId::Udp,
&dst_addr,
Some(&src_addr),
knet::LinkFlags::NONE) {
if let Some(os_err) = e.raw_os_error() {
if os_err != libc::EADDRINUSE {
- println!("Error from link_set_config(2): {}", e);
+ println!("Error from link_set_config(2): {e}");
return Err(e);
} else {
// In use - clear handle1 and try next pair of ports
knet::link_clear_config(handle1, hostid2, 0)?;
}
} else {
return Err(Error::new(ErrorKind::Other, "Error returned from link_set_config(1) was not an os_error"));
}
}
println!("Bound to ports {} & {}",p, p+1);
return Ok(p+2)
}
}
Err(Error::new(ErrorKind::Other, "No ports available"))
}
// Finish configuring links
fn configure_link(knet_handle: knet::Handle, our_hostid: &knet::HostId, other_hostid: &knet::HostId) -> Result<()>
{
if let Err(e) = knet::handle_enable_sock_notify(knet_handle, our_hostid.to_u16() as u64, Some(sock_notify_fn)) {
- println!("Error from handle_enable_sock_notify: {}", e);
+ println!("Error from handle_enable_sock_notify: {e}");
return Err(e);
}
if let Err(e) = knet::link_enable_status_change_notify(knet_handle, our_hostid.to_u16() as u64, Some(link_notify_fn)) {
- println!("Error from handle_enable_link_notify: {}", e);
+ println!("Error from handle_enable_link_notify: {e}");
return Err(e);
}
if let Err(e) = knet::host_enable_status_change_notify(knet_handle, our_hostid.to_u16() as u64, Some(host_notify_fn)) {
- println!("Error from handle_enable_host_notify: {}", e);
+ println!("Error from handle_enable_host_notify: {e}");
return Err(e);
}
if let Err(e) = knet::handle_enable_filter(knet_handle, our_hostid.to_u16() as u64, Some(filter_fn)) {
- println!("Error from handle_enable_filter: {}", e);
+ println!("Error from handle_enable_filter: {e}");
return Err(e);
}
if let Err(e) = knet::handle_enable_pmtud_notify(knet_handle, our_hostid.to_u16() as u64, Some(pmtud_fn)) {
- println!("Error from handle_enable_pmtud_notify: {}", e);
+ println!("Error from handle_enable_pmtud_notify: {e}");
return Err(e);
}
if let Err(e) = knet::handle_enable_onwire_ver_notify(knet_handle, our_hostid.to_u16() as u64, Some(onwire_fn)) {
- println!("Error from handle_enable_onwire_ver_notify: {}", e);
+ println!("Error from handle_enable_onwire_ver_notify: {e}");
return Err(e);
}
match knet::handle_add_datafd(knet_handle, 0, CHANNEL) {
Ok((fd,chan)) => {
- println!("Added datafd, fd={}, channel={}", fd, chan);
+ println!("Added datafd, fd={fd}, channel={chan}");
},
Err(e) => {
- println!("Error from add_datafd: {}", e);
+ println!("Error from add_datafd: {e}");
return Err(e);
}
}
if let Err(e) = knet::handle_crypto_rx_clear_traffic(knet_handle, knet::RxClearTraffic::Allow) {
- println!("Error from handle_crypto_rx_clear_traffic: {}", e);
+ println!("Error from handle_crypto_rx_clear_traffic: {e}");
return Err(e);
}
if let Err(e) = knet::link_set_enable(knet_handle, other_hostid, 0, true) {
- println!("Error from set_link_enable(true): {}", e);
+ println!("Error from set_link_enable(true): {e}");
return Err(e);
}
if let Err(e) = knet::link_set_ping_timers(knet_handle, other_hostid, 0,
500, 1000, 1024) {
- println!("Error from set_link_ping_timers: {}", e);
+ println!("Error from set_link_ping_timers: {e}");
return Err(e);
}
match knet::link_get_ping_timers(knet_handle, other_hostid, 0) {
Ok((a,b,c)) => {
if a != 500 || b != 1000 || c != 1024 {
- println!("get_link_ping_timers returned wrong values {}, {},{} (s/b 500,1000,1024)",
- a,b,c);
+ println!("get_link_ping_timers returned wrong values {a}, {b},{c} (s/b 500,1000,1024)");
return Err(Error::new(ErrorKind::Other, "Error in ping timers"));
}
},
Err(e) => {
- println!("Error from set_link_ping_timers: {}", e);
+ println!("Error from set_link_ping_timers: {e}");
return Err(e);
}
}
if let Err(e) = knet::handle_setfwd(knet_handle, true) {
- println!("Error from setfwd(true): {}", e);
+ println!("Error from setfwd(true): {e}");
return Err(e);
}
// Check status
let data_fd =
match knet::handle_get_datafd(knet_handle, CHANNEL) {
Ok(f) => {
- println!("got datafd {} for channel", f);
+ println!("got datafd {f} for channel");
f
}
Err(e) => {
- println!("Error from handle_get_datafd: {}", e);
+ println!("Error from handle_get_datafd: {e}");
return Err(e);
}
};
match knet::handle_get_channel(knet_handle, data_fd) {
Ok(c) =>
if c != CHANNEL {
- println!("handle_get_channel returned wrong channel ID: {}, {}",c, CHANNEL);
+ println!("handle_get_channel returned wrong channel ID: {c}, {CHANNEL}");
return Err(Error::new(ErrorKind::Other, "Error in handle_get_channel"));
}
Err(e) => {
- println!("Error from handle_get_channel: {}", e);
+ println!("Error from handle_get_channel: {e}");
return Err(e);
}
}
match knet::link_get_enable(knet_handle, other_hostid, 0) {
Ok(b) => if !b {
println!("link not enabled (according to link_get_enable()");
},
Err(e) => {
- println!("Error from link_get_enable: {}", e);
+ println!("Error from link_get_enable: {e}");
return Err(e);
}
}
Ok(())
}
fn recv_stuff(handle: knet::Handle, host: knet::HostId) -> Result<()>
{
let buf = [0u8; 1024];
loop {
match knet::recv(handle, &buf, CHANNEL) {
Ok(len) => {
let recv_len = len as usize;
if recv_len == 0 {
break; // EOF??
} else {
let s = String::from_utf8(buf[0..recv_len].to_vec()).unwrap();
println!("recvd on {}: {} {:?} {} ", host, recv_len, &buf[0..recv_len], s);
if s == *"QUIT" {
- println!("got QUIT on {}, exitting", host);
+ println!("got QUIT on {host}, exitting");
break;
}
}
}
Err(e) => {
if e.kind() == ErrorKind::WouldBlock {
thread::sleep(get_scaled_tmo(100));
} else {
- println!("recv failed: {}", e);
+ println!("recv failed: {e}");
return Err(e);
}
}
}
}
Ok(())
}
fn close_handle(handle: knet::Handle, remnode: u16) -> Result<()>
{
let other_hostid = knet::HostId::new(remnode);
if let Err(e) = knet::handle_setfwd(handle, false) {
- println!("Error from setfwd 1 (false): {}", e);
+ println!("Error from setfwd 1 (false): {e}");
return Err(e);
}
let data_fd =
match knet::handle_get_datafd(handle, CHANNEL) {
Ok(f) => {
- println!("got datafd {} for channel", f);
+ println!("got datafd {f} for channel");
f
}
Err(e) => {
- println!("Error from handle_get_datafd: {}", e);
+ println!("Error from handle_get_datafd: {e}");
return Err(e);
}
};
if let Err(e) = knet::handle_remove_datafd(handle, data_fd) {
- println!("Error from handle_remove_datafd: {}", e);
+ println!("Error from handle_remove_datafd: {e}");
return Err(e);
}
if let Err(e) = knet::link_set_enable(handle, &other_hostid, 0, false) {
- println!("Error from set_link_enable(false): {}", e);
+ println!("Error from set_link_enable(false): {e}");
return Err(e);
}
if let Err(e) = knet::link_clear_config(handle, &other_hostid, 0) {
- println!("clear config failed: {}", e);
+ println!("clear config failed: {e}");
return Err(e);
}
if let Err(e) = knet::host_remove(handle, &other_hostid) {
- println!("host remove failed: {}", e);
+ println!("host remove failed: {e}");
return Err(e);
}
if let Err(e) = knet::handle_free(handle) {
- println!("handle_free failed: {}", e);
+ println!("handle_free failed: {e}");
return Err(e);
}
Ok(())
}
fn set_compress(handle: knet::Handle) -> Result<()>
{
let compress_config = knet::CompressConfig {
compress_model: "zlib".to_string(),
compress_threshold : 10,
compress_level: 1,
};
if let Err(e) = knet::handle_compress(handle, &compress_config) {
- println!("Error from handle_compress: {}", e);
+ println!("Error from handle_compress: {e}");
Err(e)
} else {
Ok(())
}
}
fn set_crypto(handle: knet::Handle) -> Result<()>
{
let private_key = [55u8; 2048];
// Add some crypto
let crypto_config = knet::CryptoConfig {
crypto_model: "openssl".to_string(),
crypto_cipher_type: "aes256".to_string(),
crypto_hash_type: "sha256".to_string(),
private_key: &private_key,
};
if let Err(e) = knet::handle_crypto_set_config(handle, &crypto_config, 1) {
- println!("Error from handle_crypto_set_config: {}", e);
+ println!("Error from handle_crypto_set_config: {e}");
return Err(e);
}
if let Err(e) = knet::handle_crypto_use_config(handle, 1) {
- println!("Error from handle_crypto_use_config: {}", e);
+ println!("Error from handle_crypto_use_config: {e}");
return Err(e);
}
if let Err(e) = knet::handle_crypto_rx_clear_traffic(handle, knet::RxClearTraffic::Disallow) {
- println!("Error from handle_crypto_rx_clear_traffic: {}", e);
+ println!("Error from handle_crypto_rx_clear_traffic: {e}");
return Err(e);
}
Ok(())
}
fn send_messages(handle: knet::Handle, send_quit: bool) -> Result<()>
{
let mut buf : [u8; 20] = [b'0'; 20];
for i in 0..10 {
buf[i as usize + 1] = i + b'0';
match knet::send(handle, &buf, CHANNEL) {
Ok(len) => {
if len as usize != buf.len() {
println!("sent {} bytes instead of {}", len, buf.len());
}
},
Err(e) => {
- println!("send failed: {}", e);
+ println!("send failed: {e}");
return Err(e);
}
}
}
let s = String::from("SYNC TEST").into_bytes();
if let Err(e) = knet::send_sync(handle, &s, CHANNEL) {
- println!("send_sync failed: {}", e);
+ println!("send_sync failed: {e}");
return Err(e);
}
if send_quit {
// Sleep to allow messages to calm down before we tell the RX thread to quit
thread::sleep(get_scaled_tmo(3000));
let b = String::from("QUIT").into_bytes();
match knet::send(handle, &b, CHANNEL) {
Ok(len) => {
if len as usize != b.len() {
println!("sent {} bytes instead of {}", len, b.len());
}
},
Err(e) => {
- println!("send failed: {}", e);
+ println!("send failed: {e}");
return Err(e);
}
}
}
Ok(())
}
fn test_link_host_list(handle: knet::Handle) -> Result<()>
{
match knet::host_get_host_list(handle) {
Ok(hosts) => {
for i in &hosts {
- print!("host {}: links: ", i);
+ print!("host {i}: links: ");
match knet::link_get_link_list(handle, i) {
Ok(ll) => {
for j in ll {
- print!(" {}",j);
+ print!(" {j}");
}
},
Err(e) => {
- println!("link_get_link_list failed: {}", e);
+ println!("link_get_link_list failed: {e}");
return Err(e);
}
}
println!();
}
}
Err(e) => {
- println!("link_get_host_list failed: {}", e);
+ println!("link_get_host_list failed: {e}");
return Err(e);
}
}
Ok(())
}
// Try some metadata calls
fn test_metadata_calls(handle: knet::Handle, host: &knet::HostId) -> Result<()>
{
if let Err(e) = knet::handle_set_threads_timer_res(handle, 190000) {
- println!("knet_handle_set_threads_timer_res failed: {:?}", e);
+ println!("knet_handle_set_threads_timer_res failed: {e:?}");
return Err(e);
}
match knet::handle_get_threads_timer_res(handle) {
Ok(v) => {
if v != 190000 {
- println!("knet_handle_get_threads_timer_res returned wrong value {}", v);
+ println!("knet_handle_get_threads_timer_res returned wrong value {v}");
}
},
Err(e) => {
- println!("knet_handle_set_threads_timer_res failed: {:?}", e);
+ println!("knet_handle_set_threads_timer_res failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::handle_pmtud_set(handle, 1000) {
- println!("knet_handle_pmtud_set failed: {:?}", e);
+ println!("knet_handle_pmtud_set failed: {e:?}");
return Err(e);
}
match knet::handle_pmtud_get(handle) {
Ok(v) => {
if v != 1000 {
- println!("knet_handle_pmtud_get returned wrong value {} (ALLOWED)", v);
+ println!("knet_handle_pmtud_get returned wrong value {v} (ALLOWED)");
// Don't fail on this, it might not have been set yet
}
},
Err(e) => {
- println!("knet_handle_pmtud_get failed: {:?}", e);
+ println!("knet_handle_pmtud_get failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::handle_pmtud_setfreq(handle, 1000) {
- println!("knet_handle_pmtud_setfreq failed: {:?}", e);
+ println!("knet_handle_pmtud_setfreq failed: {e:?}");
return Err(e);
}
match knet::handle_pmtud_getfreq(handle) {
Ok(v) => {
if v != 1000 {
- println!("knet_handle_pmtud_getfreq returned wrong value {}", v);
+ println!("knet_handle_pmtud_getfreq returned wrong value {v}");
}
},
Err(e) => {
- println!("knet_handle_pmtud_getfreq failed: {:?}", e);
+ println!("knet_handle_pmtud_getfreq failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::handle_set_transport_reconnect_interval(handle, 100) {
- println!("knet_handle_set_transport_reconnect_interval failed: {:?}", e);
+ println!("knet_handle_set_transport_reconnect_interval failed: {e:?}");
return Err(e);
}
match knet::handle_get_transport_reconnect_interval(handle) {
Ok(v) => {
if v != 100 {
- println!("knet_handle_get_transport_reconnect_interval {}", v);
+ println!("knet_handle_get_transport_reconnect_interval {v}");
}
},
Err(e) => {
- println!("knet_handle_get_transport_reconnect_interval failed: {:?}", e);
+ println!("knet_handle_get_transport_reconnect_interval failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::link_set_pong_count(handle, host, 0, 4) {
- println!("knet_link_set_pong_count failed: {:?}", e);
+ println!("knet_link_set_pong_count failed: {e:?}");
return Err(e);
}
match knet::link_get_pong_count(handle, host, 0) {
Ok(v) => {
if v != 4 {
- println!("knet_link_get_pong_count returned wrong value {}", v);
+ println!("knet_link_get_pong_count returned wrong value {v}");
}
},
Err(e) => {
- println!("knet_link_get_pong_count failed: {:?}", e);
+ println!("knet_link_get_pong_count failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::host_set_policy(handle, host, knet::LinkPolicy::Active) {
- println!("knet_host_set_policy failed: {:?}", e);
+ println!("knet_host_set_policy failed: {e:?}");
return Err(e);
}
match knet::host_get_policy(handle, host) {
Ok(v) => {
if v != knet::LinkPolicy::Active {
- println!("knet_host_get_policy returned wrong value {}", v);
+ println!("knet_host_get_policy returned wrong value {v}");
}
},
Err(e) => {
- println!("knet_host_get_policy failed: {:?}", e);
+ println!("knet_host_get_policy failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::link_set_priority(handle, host, 0, 5) {
- println!("knet_link_set_priority failed: {:?}", e);
+ println!("knet_link_set_priority failed: {e:?}");
return Err(e);
}
match knet::link_get_priority(handle, host, 0) {
Ok(v) => {
if v != 5 {
- println!("knet_link_get_priority returned wrong value {}", v);
+ println!("knet_link_get_priority returned wrong value {v}");
}
},
Err(e) => {
- println!("knet_link_get_priority failed: {:?}", e);
+ println!("knet_link_get_priority failed: {e:?}");
return Err(e);
}
}
let name = match knet::host_get_name_by_host_id(handle, host) {
Ok(n) => {
- println!("Returned host name is {}", n);
+ println!("Returned host name is {n}");
n
},
Err(e) => {
- println!("knet_host_get_name_by_host_id failed: {:?}", e);
+ println!("knet_host_get_name_by_host_id failed: {e:?}");
return Err(e);
}
};
match knet::host_get_id_by_host_name(handle, &name) {
Ok(n) => {
- println!("Returned host id is {}", n);
+ println!("Returned host id is {n}");
if n != *host {
println!("Returned host id is not 2");
return Err(Error::new(ErrorKind::Other, "Error in get_id_by_host_name"));
}
},
Err(e) => {
- println!("knet_host_get_id_by_host_name failed: {:?}", e);
+ println!("knet_host_get_id_by_host_name failed: {e:?}");
return Err(e);
}
}
match knet::link_get_config(handle, host, 0) {
Ok((t, s, d, _f)) => {
println!("Got link config: {}, {:?}, {:?}", t.to_string(),s,d);
},
Err(e) => {
- println!("knet_link_get_config failed: {:?}", e);
+ println!("knet_link_get_config failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::handle_set_host_defrag_bufs(handle, 4, 32, 25, knet::DefragReclaimPolicy::Absolute) {
- println!("handle_config_set_host_defrag_bufs failed: {:?}", e);
+ println!("handle_config_set_host_defrag_bufs failed: {e:?}");
return Err(e);
}
match knet::handle_get_host_defrag_bufs(handle) {
Ok((min, max, shrink, policy)) => {
if min != 4 || max != 32 ||
shrink != 25 || policy != knet::DefragReclaimPolicy::Absolute {
println!("handle_config_get_host_defrag_bufs returned bad values");
- println!("Got {},{},{},{}. expected 4,32,2,Absolute", min, max, shrink, policy);
+ println!("Got {min},{max},{shrink},{policy}. expected 4,32,2,Absolute");
} else {
- println!("Defrag params correct: {},{},{},{}", min, max, shrink, policy);
+ println!("Defrag params correct: {min},{max},{shrink},{policy}");
}
}
Err(e) => {
- println!("handle_config_get_host_defrag_bufs failed: {:?}", e);
+ println!("handle_config_get_host_defrag_bufs failed: {e:?}");
return Err(e);
}
}
// Can't set this to anything different
if let Err(e) = knet::handle_set_onwire_ver(handle, 1) {
- println!("knet_link_set_onwire_ver failed: {:?}", e);
+ println!("knet_link_set_onwire_ver failed: {e:?}");
return Err(e);
}
match knet::handle_get_onwire_ver(handle, host) {
Ok((min, max, ver)) => {
- println!("get_onwire_ver: Got onwire ver: {}/{}/{}", min, max, ver);
+ println!("get_onwire_ver: Got onwire ver: {min}/{max}/{ver}");
},
Err(e) => {
- println!("knet_link_get_onwire_ver failed: {:?}", e);
+ println!("knet_link_get_onwire_ver failed: {e:?}");
return Err(e);
}
}
// Logging
match knet::log_get_subsystem_name(3) {
- Ok(n) => println!("subsystem name for 3 is {}", n),
+ Ok(n) => println!("subsystem name for 3 is {n}"),
Err(e) => {
- println!("knet_log_get_subsystem_name failed: {:?}", e);
+ println!("knet_log_get_subsystem_name failed: {e:?}");
return Err(e);
}
}
match knet::log_get_subsystem_id("TX") {
- Ok(n) => println!("subsystem ID for TX is {}", n),
+ Ok(n) => println!("subsystem ID for TX is {n}"),
Err(e) => {
- println!("knet_log_get_subsystem_id failed: {:?}", e);
+ println!("knet_log_get_subsystem_id failed: {e:?}");
return Err(e);
}
}
match knet::log_get_loglevel_id("DEBUG") {
- Ok(n) => println!("loglevel ID for DEBUG is {}", n),
+ Ok(n) => println!("loglevel ID for DEBUG is {n}"),
Err(e) => {
- println!("knet_log_get_loglevel_id failed: {:?}", e);
+ println!("knet_log_get_loglevel_id failed: {e:?}");
return Err(e);
}
}
match knet::log_get_loglevel_name(1) {
- Ok(n) => println!("loglevel name for 1 is {}", n),
+ Ok(n) => println!("loglevel name for 1 is {n}"),
Err(e) => {
- println!("knet_log_get_loglevel_name failed: {:?}", e);
+ println!("knet_log_get_loglevel_name failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::log_set_loglevel(handle, knet::SubSystem::Handle , knet::LogLevel::Debug) {
- println!("knet_log_set_loglevel failed: {:?}", e);
+ println!("knet_log_set_loglevel failed: {e:?}");
return Err(e);
}
match knet::log_get_loglevel(handle, knet::SubSystem::Handle) {
- Ok(n) => println!("loglevel for Handle is {}", n),
+ Ok(n) => println!("loglevel for Handle is {n}"),
Err(e) => {
- println!("knet_log_get_loglevel failed: {:?}", e);
+ println!("knet_log_get_loglevel failed: {e:?}");
return Err(e);
}
}
Ok(())
}
fn test_acl(handle: knet::Handle, host: &knet::HostId, low_port: u16) -> Result<()>
{
if let Err(e) = knet::handle_enable_access_lists(handle, true) {
- println!("Error from handle_enable_access_lists: {:?}", e);
+ println!("Error from handle_enable_access_lists: {e:?}");
return Err(e);
}
// Dynamic link for testing ACL APIs (it never gets used)
if let Err(e) = setup_dynamic_link(handle, host, 1, low_port) {
- println!("Error from link_set_config (dynamic): {}", e);
+ println!("Error from link_set_config (dynamic): {e}");
return Err(e);
}
// These ACLs are nonsense on stilts
if let Err(e) = knet::link_add_acl(handle, host, 1,
&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8003_u16),
&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8003_u16),
knet::AclCheckType::Address, knet::AclAcceptReject::Reject) {
- println!("Error from link_add_acl: {:?}", e);
+ println!("Error from link_add_acl: {e:?}");
return Err(e);
}
if let Err(e) = knet::link_insert_acl(handle, host, 1,
0,
&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 8004_u16),
&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 8004_u16),
knet::AclCheckType::Address, knet::AclAcceptReject::Reject) {
- println!("Error from link_add_acl: {:?}", e);
+ println!("Error from link_add_acl: {e:?}");
return Err(e);
}
if let Err(e) = knet::link_rm_acl(handle, host, 1,
&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8003_u16),
&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8003_u16),
knet::AclCheckType::Address, knet::AclAcceptReject::Reject) {
- println!("Error from link_rm_acl: {:?}", e);
+ println!("Error from link_rm_acl: {e:?}");
return Err(e);
}
if let Err(e) = knet::link_clear_acl(handle, host, 1) {
- println!("Error from link_clear_acl: {:?}", e);
+ println!("Error from link_clear_acl: {e:?}");
return Err(e);
}
// Get rid of this link before it messes things up
if let Err(e) = knet::link_clear_config(handle, host, 1) {
- println!("clear config (dynamic) failed: {}", e);
+ println!("clear config (dynamic) failed: {e}");
return Err(e);
}
if let Err(e) = knet::handle_enable_access_lists(handle, false) {
- println!("Error from handle_enable_access_lists: {:?}", e);
+ println!("Error from handle_enable_access_lists: {e:?}");
return Err(e);
}
Ok(())
}
fn main() -> Result<()>
{
// Start with some non-handle information
match knet::get_crypto_list() {
Ok(l) => {
print!("Crypto models:");
for i in &l {
print!(" {}", i.name);
}
println!();
}
Err(e) => {
- println!("link_get_crypto_list failed: {:?}", e);
+ println!("link_get_crypto_list failed: {e:?}");
return Err(e);
}
}
match knet::get_compress_list() {
Ok(l) => {
print!("Compress models:");
for i in &l {
print!(" {}", i.name);
}
println!();
}
Err(e) => {
- println!("link_get_compress_list failed: {:?}", e);
+ println!("link_get_compress_list failed: {e:?}");
return Err(e);
}
}
match knet::get_transport_list() {
Ok(l) => {
print!("Transports:");
for i in &l {
print!(" {}", i.name);
}
println!();
}
Err(e) => {
- println!("link_get_transport_list failed: {:?}", e);
+ println!("link_get_transport_list failed: {e:?}");
return Err(e);
}
}
let host1 = knet::HostId::new(1);
let host2 = knet::HostId::new(2);
// Now test traffic
let handle1 = setup_node(&host1, &host2, "host2")?;
let handle2 = setup_node(&host2, &host1, "host1")?;
let low_port = setup_links(handle1, &host1, handle2, &host2)?;
configure_link(handle1, &host1, &host2)?;
configure_link(handle2, &host2, &host1)?;
// Copy stuff for the threads
let handle1_clone = handle1;
let handle2_clone = handle2;
let host1_clone = host1;
let host2_clone = host2;
// Wait for links to start
thread::sleep(get_scaled_tmo(10000));
test_link_host_list(handle1)?;
test_link_host_list(handle2)?;
// Start recv threads for each handle
let thread_handles = vec![
spawn(move || recv_stuff(handle1_clone, host1_clone)),
spawn(move || recv_stuff(handle2_clone, host2_clone))
];
send_messages(handle1, false)?;
send_messages(handle2, false)?;
thread::sleep(get_scaled_tmo(3000));
set_crypto(handle1)?;
set_crypto(handle2)?;
set_compress(handle1)?;
set_compress(handle2)?;
thread::sleep(get_scaled_tmo(3000));
send_messages(handle1, true)?;
send_messages(handle2, true)?;
test_acl(handle1, &host2, low_port)?;
// Wait for recv threads to finish
for handle in thread_handles {
if let Err(error) = handle.join() {
- println!("thread join error: {:?}", error);
+ println!("thread join error: {error:?}");
}
}
// Try some statses
match knet::handle_get_stats(handle1) {
- Ok(s) => println!("handle stats: {}", s),
+ Ok(s) => println!("handle stats: {s}"),
Err(e) => {
- println!("handle_get_stats failed: {:?}", e);
+ println!("handle_get_stats failed: {e:?}");
return Err(e);
}
}
match knet::host_get_status(handle1, &host2) {
- Ok(s) => println!("host status: {}", s),
+ Ok(s) => println!("host status: {s}"),
Err(e) => {
- println!("host_get_status failed: {:?}", e);
+ println!("host_get_status failed: {e:?}");
return Err(e);
}
}
match knet::link_get_status(handle1, &host2, 0) {
- Ok(s) => println!("link status: {}", s),
+ Ok(s) => println!("link status: {s}"),
Err(e) => {
- println!("link_get_status failed: {:?}", e);
+ println!("link_get_status failed: {e:?}");
return Err(e);
}
}
if let Err(e) = knet::handle_clear_stats(handle1, knet::ClearStats::Handle) {
- println!("handle_clear_stats failed: {:?}", e);
+ println!("handle_clear_stats failed: {e:?}");
return Err(e);
}
test_metadata_calls(handle1, &knet::HostId::new(2))?;
close_handle(handle1, 2)?;
close_handle(handle2, 1)?;
// Sleep to see if log thread dies
thread::sleep(get_scaled_tmo(3000));
Ok(())
}
diff --git a/libnozzle/bindings/rust/tests/src/bin/nozzle-test.rs b/libnozzle/bindings/rust/tests/src/bin/nozzle-test.rs
index 79638c86..acd957c7 100644
--- a/libnozzle/bindings/rust/tests/src/bin/nozzle-test.rs
+++ b/libnozzle/bindings/rust/tests/src/bin/nozzle-test.rs
@@ -1,245 +1,245 @@
// Testing the Nozzle Rust APIs
//
// Copyright (C) 2021-2023 Red Hat, Inc.
//
// All rights reserved.
//
// Author: Christine Caulfield (ccaulfi@redhat.com)
//
use nozzle_bindings::nozzle_bindings as nozzle;
use std::io::{Result, Error, ErrorKind, BufWriter, Write};
use std::fmt::Write as fmtwrite;
use std::{thread, time};
use std::fs::File;
use std::fs;
use tempfile::tempdir;
const SKIP: i32 = 77;
fn main() -> Result<()>
{
// We must be root
if unsafe { libc::geteuid() != 0 } {
std::process::exit(SKIP);
}
// Run in a random tmpdir so we don't clash with other instances
let tmp_path = tempdir()?;
let tmp_dir = match tmp_path.path().to_str() {
Some(td) => td,
None => {
println!("Error creating temp path for running");
return Err(Error::new(ErrorKind::Other, "Error creating temp path"));
}
};
std::env::set_current_dir(tmp_dir)?;
// Let the OS generate a tap name
let mut nozzle_name = String::from("");
let handle = match nozzle::open(&mut nozzle_name, tmp_dir) {
Ok(h) => {
- println!("Opened device {}", nozzle_name);
+ println!("Opened device {nozzle_name}");
h
},
Err(e) => {
- println!("Error from open: {}", e);
+ println!("Error from open: {e}");
return Err(e);
}
};
// Get default state for checking reset_* calls later
let saved_mtu = match nozzle::get_mtu(handle) {
Ok(m) => m,
Err(e) => {
- println!("Error from get_mtu: {}", e);
+ println!("Error from get_mtu: {e}");
return Err(e);
}
};
let saved_mac = match nozzle::get_mac(handle) {
Ok(m) => m,
Err(e) => {
- println!("Error from get_mac: {}", e);
+ println!("Error from get_mac: {e}");
return Err(e);
}
};
// Play with APIs
if let Err(e) = nozzle::add_ip(handle, "192.160.100.1", "24") {
- println!("Error from add_ip: {}", e);
+ println!("Error from add_ip: {e}");
return Err(e);
}
if let Err(e) = nozzle::add_ip(handle, "192.160.100.2", "24") {
- println!("Error from add_ip2: {}", e);
+ println!("Error from add_ip2: {e}");
return Err(e);
}
if let Err(e) = nozzle::add_ip(handle, "192.160.100.3", "24") {
- println!("Error from add_ip3: {}", e);
+ println!("Error from add_ip3: {e}");
return Err(e);
}
if let Err(e) = nozzle::set_mac(handle, "AA:00:04:00:22:01") {
- println!("Error from set_mac: {}", e);
+ println!("Error from set_mac: {e}");
return Err(e);
}
if let Err(e) = nozzle::set_mtu(handle, 157) {
- println!("Error from set_mtu: {}", e);
+ println!("Error from set_mtu: {e}");
return Err(e);
}
if let Err(e) = nozzle::set_up(handle) {
- println!("Error from set_up: {}", e);
+ println!("Error from set_up: {e}");
return Err(e);
}
// Create the 'up' script so we can test the run_updown() function,
let up_path = std::path::Path::new("up.d");
if let Err(e) = fs::create_dir_all(up_path) {
- eprintln!("Error creating up.d directory: {:?}", e);
+ eprintln!("Error creating up.d directory: {e:?}");
return Err(e);
}
let mut up_filename = String::new();
- if let Err(e) = write!(up_filename, "up.d/{}", nozzle_name) {
- eprintln!("Error making up.d filename: {:?}", e);
+ if let Err(e) = write!(up_filename, "up.d/{nozzle_name}") {
+ eprintln!("Error making up.d filename: {e:?}");
return Err(Error::new(ErrorKind::Other, "Error making up.d filename"));
}
match File::create(&up_filename) {
Err(e) => {
println!("Cannot create up.d file {}: {}", &up_filename, e);
return Err(e);
}
Ok(fl) => {
let mut f = BufWriter::new(fl);
writeln!(f, "#!/bin/sh\necho 'This is a test of an \"Up\" script'")?;
}
}
// A grotty way to do chmod, but normally this would be distributed by the sysadmin
unsafe {
let up_cstring = std::ffi::CString::new(up_filename.clone()).unwrap();
libc::chmod(up_cstring.as_ptr(), 0o700);
}
match nozzle::run_updown(handle, nozzle::Action::Up) {
- Ok(s) => println!("Returned from Up script: {}", s),
+ Ok(s) => println!("Returned from Up script: {s}"),
Err(e) => {
- println!("Error from run_updown: {}", e);
+ println!("Error from run_updown: {e}");
return Err(e);
}
}
// Tidy up after ourself - remove the up.d/tapX file
fs::remove_file(&up_filename)?;
fs::remove_dir("up.d")?;
match nozzle::get_ips(handle) {
Ok(ips) => {
print!("Got IPs:");
for i in ips {
- print!(" {}", i);
+ print!(" {i}");
}
println!();
},
Err(e) => {
- println!("Error from get_ips: {}", e);
+ println!("Error from get_ips: {e}");
return Err(e);
}
}
match nozzle::get_mtu(handle) {
- Ok(m) => println!("Got mtu: {}", m),
+ Ok(m) => println!("Got mtu: {m}"),
Err(e) => {
- println!("Error from get_ips: {}", e);
+ println!("Error from get_ips: {e}");
return Err(e);
}
}
match nozzle::get_mac(handle) {
- Ok(m) => println!("Got mac: {}", m),
+ Ok(m) => println!("Got mac: {m}"),
Err(e) => {
- println!("Error from get_ips: {}", e);
+ println!("Error from get_ips: {e}");
return Err(e);
}
}
match nozzle::get_fd(handle) {
- Ok(f) => println!("Got FD: {}", f),
+ Ok(f) => println!("Got FD: {f}"),
Err(e) => {
- println!("Error from get_fd: {}", e);
+ println!("Error from get_fd: {e}");
return Err(e);
}
}
match nozzle::get_handle_by_name(&nozzle_name) {
Ok(h) => if h != handle {
return Err(Error::new(ErrorKind::Other, "get_handle_by_name returned wrong value"));
}
Err(e) => {
- println!("Error from get_ips: {}", e);
+ println!("Error from get_ips: {e}");
return Err(e);
}
}
match nozzle::get_name_by_handle(handle) {
Ok(n) => if n != nozzle_name {
- println!("n: {}, nozzle_name: {}", n, nozzle_name);
+ println!("n: {n}, nozzle_name: {nozzle_name}");
return Err(Error::new(ErrorKind::Other, "get_name_by_handle returned wrong name"));
}
Err(e) => {
- println!("Error from get_ips: {}", e);
+ println!("Error from get_ips: {e}");
return Err(e);
}
}
// Wait a little while in case user wants to check with 'ip' command
thread::sleep(time::Duration::from_millis(1000));
if let Err(e) = nozzle::del_ip(handle, "192.160.100.3", "24") {
- println!("Error from del_ip: {}", e);
+ println!("Error from del_ip: {e}");
return Err(e);
}
if let Err(e) = nozzle::reset_mtu(handle) {
- println!("Error from reset_mtu: {}", e);
+ println!("Error from reset_mtu: {e}");
return Err(e);
}
match nozzle::get_mtu(handle) {
Ok(m) => {
if m != saved_mtu {
- println!("Got default MTU of {}, not {}", m, saved_mtu);
+ println!("Got default MTU of {m}, not {saved_mtu}");
}
}
Err(e) => {
- println!("Error from get_ips: {}", e);
+ println!("Error from get_ips: {e}");
return Err(e);
}
}
if let Err(e) = nozzle::reset_mac(handle) {
- println!("Error from reset_mac: {}", e);
+ println!("Error from reset_mac: {e}");
return Err(e);
}
match nozzle::get_mac(handle) {
Ok(m) => {
if m != saved_mac {
- println!("Got default MAC of {}, not {}", m, saved_mac);
+ println!("Got default MAC of {m}, not {saved_mac}");
}
}
Err(e) => {
- println!("Error from get_ips: {}", e);
+ println!("Error from get_ips: {e}");
return Err(e);
}
}
if let Err(e) = nozzle::set_down(handle){
- println!("Error from set_down: {}", e);
+ println!("Error from set_down: {e}");
return Err(e);
}
if let Err(e) = nozzle::close(handle) {
- println!("Error from open: {}", e);
+ println!("Error from open: {e}");
return Err(e);
}
Ok(())
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Feb 24, 8:05 AM (22 h, 10 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1460600
Default Alt Text
(110 KB)

Event Timeline