diff --git a/libknet/bindings/rust/src/knet_bindings.rs b/libknet/bindings/rust/src/knet_bindings.rs
index cedf9f42..3eb3df5f 100644
--- a/libknet/bindings/rust/src/knet_bindings.rs
+++ b/libknet/bindings/rust/src/knet_bindings.rs
@@ -1,2561 +1,2588 @@
 // 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)]
 #![allow(clippy::bad_bit_mask)]
 
 // 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, 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}};
+		handle: Handle{knet_handle: logbuf.knet_h as u64, clone: true}};
 
 	    if let Err(e) = sender.send(rmsg) {
 		println!("Error sending log message: {e}");
 	    }
 	}
     }
 }
 
 
-#[derive(Copy, Clone, PartialEq, Eq)]
-#[repr(transparent)]
 /// a handle into the knet library, returned from [handle_new]
 pub struct Handle {
-    knet_handle: u64,
+    pub knet_handle: u64,
+    clone: bool, // clone Handles don't trigger knet_handle_free()
+}
+
+impl Clone for Handle {
+    fn clone(&self) -> Handle {
+	Handle {knet_handle: self.knet_handle, clone: true}
+    }
+}
+
+// Clones count as equivalent
+impl PartialEq for Handle {
+    fn eq(&self, other: &Handle) -> bool {
+	self.knet_handle == other.knet_handle
+    }
 }
 
 // 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})
+	Ok(Handle{knet_handle: res as u64, clone: false})
     }
 }
 
 /// Finish with knet, frees the handle returned by [handle_new]
-pub fn handle_free(handle: Handle) -> Result<()>
+pub fn handle_free(handle: &Handle) -> Result<()>
+{
+    if handle_free_knet_handle(handle.knet_handle) == 0 {
+	Ok(())
+    } else {
+	Err(Error::last_os_error())
+    }
+}
+
+fn handle_free_knet_handle(knet_handle: u64) -> i32
 {
     let res = unsafe {
-	ffi::knet_handle_free(handle.knet_handle as ffi::knet_handle_t)
+	ffi::knet_handle_free(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)) {
+	if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(knet_handle)) {
 	    unsafe {
 		libc::close(h.log_fd);
 	    };
 	}
 
-	HANDLE_HASH.lock().unwrap().remove(&handle.knet_handle);
-	Ok(())
-    } else {
-	Err(Error::last_os_error())
+	HANDLE_HASH.lock().unwrap().remove(&knet_handle);
+    }
+    res
+}
+
+impl Drop for Handle {
+    fn drop(self: &mut Handle) {
+	if !self.clone {
+	    handle_free_knet_handle(self.knet_handle);
+	}
     }
 }
 
 /// Enable notifications of socket state changes, set callback to 'None' to disable
-pub fn handle_enable_sock_notify(handle: Handle,
+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)>
+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<()>
+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>
+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>
+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,
+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)>
+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>
+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>
+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<()>
+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,
+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<()>
+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>
+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<()>
+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<()>
+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<()>
+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>
+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>
+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<()>
+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,
+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<()>
+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<()>
+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<()>
+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<()>
+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>
+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<()>
+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,
+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)>
+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<()>
+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<()>
+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>
+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<()>
+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<()>
+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<()>
+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>
+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>
+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>>
+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<()>
+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>
+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>
+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,
+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,
+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) ->
+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<()>
+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(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(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,
+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,
+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,
+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<()>
+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<()>
+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>
+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,
+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)>
+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,
+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>
+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,
+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>
+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>>
+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,
+pub fn link_enable_status_change_notify(handle: &Handle,
 					private_data: u64,
 					link_status_change_notify_fn: Option<LinkStatusChangeNotifyFn>) -> Result<()>
 {
     if let Some(h) = HANDLE_HASH.lock().unwrap().get_mut(&(handle.knet_handle)) {
 	h.link_status_change_notify_private_data = private_data;
 	h.link_status_change_notify_fn = link_status_change_notify_fn;
 	let res = match link_status_change_notify_fn {
 	    Some(_f) =>
 		unsafe {
 		    ffi::knet_link_enable_status_change_notify(handle.knet_handle as ffi::knet_handle_t,
 							       handle.knet_handle as *mut c_void,
 							       Some(rust_link_status_change_notify_fn))
 		},
 	    None =>
 		unsafe {
 		    ffi::knet_link_enable_status_change_notify(handle.knet_handle as ffi::knet_handle_t,
 							       handle.knet_handle as *mut c_void,
 							       None)
 		},
 	};
 	if res == 0 {
 	    return Ok(());
 	} else {
 	    return Err(Error::last_os_error());
 	}
     }
     Err(Error::new(ErrorKind::Other, "Rust handle not found"))
 
 }
 
 /// Link stats
 pub struct LinkStats {
     pub tx_data_packets: u64,
     pub rx_data_packets: u64,
     pub tx_data_bytes: u64,
     pub rx_data_bytes: u64,
     pub rx_ping_packets: u64,
     pub tx_ping_packets: u64,
     pub rx_ping_bytes: u64,
     pub tx_ping_bytes: u64,
     pub rx_pong_packets: u64,
     pub tx_pong_packets: u64,
     pub rx_pong_bytes: u64,
     pub tx_pong_bytes: u64,
     pub rx_pmtu_packets: u64,
     pub tx_pmtu_packets: u64,
     pub rx_pmtu_bytes: u64,
     pub tx_pmtu_bytes: u64,
     pub tx_total_packets: u64,
     pub rx_total_packets: u64,
     pub tx_total_bytes: u64,
     pub rx_total_bytes: u64,
     pub tx_total_errors: u64,
     pub tx_total_retries: u64,
     pub tx_pmtu_errors: u32,
     pub tx_pmtu_retries: u32,
     pub tx_ping_errors: u32,
     pub tx_ping_retries: u32,
     pub tx_pong_errors: u32,
     pub tx_pong_retries: u32,
     pub tx_data_errors: u32,
     pub tx_data_retries: u32,
     pub latency_min: u32,
     pub latency_max: u32,
     pub latency_ave: u32,
     pub latency_samples: u32,
     pub down_count: u32,
     pub up_count: u32,
     pub last_up_times: Vec<SystemTime>,
     pub last_down_times: Vec<SystemTime>,
 }
 // Quick & Dirty printing
 impl fmt::Display for LinkStats {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 	write!(f, "{}, ", self.tx_data_packets)?;
 	write!(f, "{}, ", self.rx_data_packets)?;
 	write!(f, "{}, ", self.tx_data_bytes)?;
 	write!(f, "{}, ", self.rx_data_bytes)?;
 	write!(f, "{}, ", self.rx_ping_packets)?;
 	write!(f, "{}, ", self.tx_ping_packets)?;
 	write!(f, "{}, ", self.rx_ping_bytes)?;
 	write!(f, "{}, ", self.tx_ping_bytes)?;
 	write!(f, "{}, ", self.rx_pong_packets)?;
 	write!(f, "{}, ", self.tx_pong_packets)?;
 	write!(f, "{}, ", self.rx_pong_bytes)?;
 	write!(f, "{}, ", self.tx_pong_bytes)?;
 	write!(f, "{}, ", self.rx_pmtu_packets)?;
 	write!(f, "{}, ", self.tx_pmtu_packets)?;
 	write!(f, "{}, ", self.rx_pmtu_bytes)?;
 	write!(f, "{}, ", self.tx_pmtu_bytes)?;
 	write!(f, "{}, ", self.tx_total_packets)?;
 	write!(f, "{}, ", self.rx_total_packets)?;
 	write!(f, "{}, ", self.tx_total_bytes)?;
 	write!(f, "{}, ", self.rx_total_bytes)?;
 	write!(f, "{}, ", self.tx_total_errors)?;
 	write!(f, "{}, ", self.tx_total_retries)?;
 	write!(f, "{}, ", self.tx_pmtu_errors)?;
 	write!(f, "{}, ", self.tx_pmtu_retries)?;
 	write!(f, "{}, ", self.tx_ping_errors)?;
 	write!(f, "{}, ", self.tx_ping_retries)?;
 	write!(f, "{}, ", self.tx_pong_errors)?;
 	write!(f, "{}, ", self.tx_pong_retries)?;
 	write!(f, "{}, ", self.tx_data_errors)?;
 	write!(f, "{}, ", self.tx_data_retries)?;
 	write!(f, "{}, ", self.latency_min)?;
 	write!(f, "{}, ", self.latency_max)?;
 	write!(f, "{}, ", self.latency_ave)?;
 	write!(f, "{}, ", self.latency_samples)?;
 	write!(f, "{}, ", self.down_count)?;
 	write!(f, "{}, ", self.up_count)?;
 	write!(f, "Last up times: ")?;
 	// There's no sensible print for SystemTime in the std library
 	// and I don't want to add dependancies here for printing as it
 	// mostly going to be the client's responsibility, so use the Debug option
 	for i in &self.last_up_times {
 	    write!(f, "{i:?}")?;
 	}
 	write!(f, " Last down times: ")?;
 	for i in &self.last_down_times {
 	    write!(f, "{i:?}")?;
 	}
 	Ok(())
     }
 }
 
 // I wish this all wasn't necessary!
 impl ffi::knet_link_stats {
     pub fn new() -> ffi::knet_link_stats {
 	ffi::knet_link_stats {
 	    tx_data_packets: 0,
 	    rx_data_packets: 0,
 	    tx_data_bytes: 0,
 	    rx_data_bytes: 0,
 	    rx_ping_packets: 0,
 	    tx_ping_packets: 0,
 	    rx_ping_bytes: 0,
 	    tx_ping_bytes: 0,
 	    rx_pong_packets: 0,
 	    tx_pong_packets: 0,
 	    rx_pong_bytes: 0,
 	    tx_pong_bytes: 0,
 	    rx_pmtu_packets: 0,
 	    tx_pmtu_packets: 0,
 	    rx_pmtu_bytes: 0,
 	    tx_pmtu_bytes: 0,
 	    tx_total_packets: 0,
 	    rx_total_packets: 0,
 	    tx_total_bytes: 0,
 	    rx_total_bytes: 0,
 	    tx_total_errors: 0,
 	    tx_total_retries: 0,
 	    tx_pmtu_errors: 0,
 	    tx_pmtu_retries: 0,
 	    tx_ping_errors: 0,
 	    tx_ping_retries: 0,
 	    tx_pong_errors: 0,
 	    tx_pong_retries: 0,
 	    tx_data_errors: 0,
 	    tx_data_retries: 0,
 	    latency_min: 0,
 	    latency_max: 0,
 	    latency_ave: 0,
 	    latency_samples: 0,
 	    down_count: 0,
 	    up_count: 0,
 	    last_up_times: [0; 16],
 	    last_down_times: [0; 16],
 	    last_up_time_index: 0,
 	    last_down_time_index: 0,
 	}
     }
 }
 impl Default for ffi::knet_link_stats {
     fn default() -> Self {
 	ffi::knet_link_stats::new()
     }
 }
 impl ffi::knet_link_status {
     pub fn new()-> ffi::knet_link_status
     {
 	ffi::knet_link_status {
 	    size: 0,
 	    src_ipaddr : [0; KNET_MAX_HOST_LEN],
 	    dst_ipaddr : [0; KNET_MAX_HOST_LEN],
 	    src_port : [0; KNET_MAX_PORT_LEN],
 	    dst_port : [0; KNET_MAX_PORT_LEN],
 	    enabled: 0,
 	    connected: 0,
 	    dynconnected: 0,
 	    pong_last: ffi::timespec{ tv_sec: 0, tv_nsec: 0},
 	    mtu: 0,
 	    proto_overhead: 0,
 	    stats: ffi::knet_link_stats::new(),
 	}
     }
 }
 impl Default for ffi::knet_link_status {
     fn default() -> Self {
 	ffi::knet_link_status::new()
     }
 }
 
 /// Link status (includes a [LinkStats])
 pub struct LinkStatus
 {
     pub src_ipaddr: String,
     pub dst_ipaddr: String,
     pub src_port: String,
     pub dst_port: String,
     pub enabled: bool,
     pub connected: bool,
     pub dynconnected: bool,
     pub pong_last: SystemTime,
     pub mtu: u32,
     pub proto_overhead: u32,
     pub stats: LinkStats,
 }
 impl LinkStatus {
     pub fn new(c_stats: ffi::knet_link_status) -> LinkStatus
     {
 	LinkStatus {
 	    src_ipaddr : crate::string_from_bytes_safe(c_stats.src_ipaddr.as_ptr(), KNET_MAX_HOST_LEN),
 	    src_port : crate::string_from_bytes_safe(c_stats.src_port.as_ptr(), KNET_MAX_HOST_LEN),
 	    dst_ipaddr : crate::string_from_bytes_safe(c_stats.dst_ipaddr.as_ptr(), KNET_MAX_HOST_LEN),
 	    dst_port : crate::string_from_bytes_safe(c_stats.dst_port.as_ptr(), KNET_MAX_HOST_LEN),
 	    enabled : crate::u8_to_bool(c_stats.enabled),
 	    connected : crate::u8_to_bool(c_stats.connected),
 	    dynconnected : crate::u8_to_bool(c_stats.dynconnected),
 	    pong_last : systemtime_from_timespec(c_stats.pong_last),
 	    mtu : c_stats.mtu,
 	    proto_overhead : c_stats.proto_overhead,
 	    stats : LinkStats::new(c_stats.stats),
 	}
     }
 }
 impl fmt::Display for LinkStatus {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 	write!(f, "src_ip_addr: {}:{}, ", self.src_ipaddr, self.src_port)?;
 	write!(f, "dst_ip_addr: {}:{}, ", self.dst_ipaddr, self.src_port)?;
 	write!(f, "enabled: {}, connected: {}, mtu: {}, overhead: {}, ",
 		 self.enabled, self.connected, self.mtu, self.proto_overhead)?;
 	write!(f, "stats: {}", self.stats)?;
 	Ok(())
     }
 }
 
 fn systemtime_from_time_t(t: u64) -> SystemTime
 {
     SystemTime::UNIX_EPOCH+Duration::from_secs(t)
 }
 
 fn systemtime_from_timespec(t: ffi::timespec) -> SystemTime
 {
     SystemTime::UNIX_EPOCH+Duration::from_secs(t.tv_sec as u64)
 	+Duration::from_nanos(t.tv_nsec as u64) // TODO may panic??
 
 }
 
 fn copy_circular_buffer_of_link_events(num: usize, times: &[ffi::time_t]) -> Vec<SystemTime>
 {
     let mut times_vec = Vec::<SystemTime>::new();
 
     for index in (0 .. num).rev() {
 	if times[index] == 0 {
 	    break
 	}
 	times_vec.push(systemtime_from_time_t(times[index] as u64)); // TODO may panic??
     }
     for index in (num+1 .. MAX_LINK_EVENTS).rev() {
 	if times[index] == 0 {
 	    break;
 	}
 	times_vec.push(systemtime_from_time_t(times[index] as u64)); // TODO may panic??
     }
     times_vec
 }
 
 const MAX_LINK_EVENTS: usize = 16;
 impl LinkStats {
     pub fn new(cstats: ffi::knet_link_stats) -> LinkStats
     {
 	let up_times = copy_circular_buffer_of_link_events(cstats.last_up_time_index as usize,
 							   &cstats.last_up_times);
 
 	let down_times = copy_circular_buffer_of_link_events(cstats.last_down_time_index as usize,
 							   &cstats.last_down_times);
 
 	LinkStats {
 	    tx_data_packets: cstats.tx_data_packets,
 	    rx_data_packets: cstats.rx_data_packets,
 	    tx_data_bytes: cstats.tx_data_bytes,
 	    rx_data_bytes: cstats.rx_data_bytes,
 	    rx_ping_packets: cstats.rx_ping_packets,
 	    tx_ping_packets: cstats.tx_ping_packets,
 	    rx_ping_bytes: cstats.rx_ping_bytes,
 	    tx_ping_bytes: cstats.tx_ping_bytes,
 	    rx_pong_packets: cstats.rx_pong_packets,
 	    tx_pong_packets: cstats.tx_pong_packets,
 	    rx_pong_bytes: cstats.rx_pong_bytes,
 	    tx_pong_bytes: cstats.tx_pong_bytes,
 	    rx_pmtu_packets: cstats.rx_pmtu_packets,
 	    tx_pmtu_packets: cstats.tx_pmtu_packets,
 	    rx_pmtu_bytes: cstats.rx_pmtu_bytes,
 	    tx_pmtu_bytes: cstats.tx_pmtu_bytes,
 	    tx_total_packets: cstats.tx_total_packets,
 	    rx_total_packets: cstats.rx_total_packets,
 	    tx_total_bytes: cstats.tx_total_bytes,
 	    rx_total_bytes: cstats.rx_total_bytes,
 	    tx_total_errors: cstats.tx_total_errors,
 	    tx_total_retries: cstats.tx_total_retries,
 	    tx_pmtu_errors: cstats.tx_pmtu_errors,
 	    tx_pmtu_retries: cstats.tx_pmtu_retries,
 	    tx_ping_errors: cstats.tx_ping_errors,
 	    tx_ping_retries: cstats.tx_ping_retries,
 	    tx_pong_errors: cstats.tx_pong_errors,
 	    tx_pong_retries: cstats.tx_pong_retries,
 	    tx_data_errors: cstats.tx_data_errors,
 	    tx_data_retries: cstats.tx_data_retries,
 	    latency_min: cstats.latency_min,
 	    latency_max: cstats.latency_max,
 	    latency_ave: cstats.latency_ave,
 	    latency_samples: cstats.latency_samples,
 	    down_count: cstats.down_count,
 	    up_count: cstats.up_count,
 	    last_up_times: up_times,
 	    last_down_times: down_times,
 	}
     }
 }
 
 /// Get the status (and stats) of a link
-pub fn link_get_status(handle: Handle, host_id: &HostId, link_id: u8) -> Result<LinkStatus>
+pub fn link_get_status(handle: &Handle, host_id: &HostId, link_id: u8) -> Result<LinkStatus>
 {
     let (res, stats) = unsafe {
 	let mut c_stats : ffi::knet_link_status = ffi::knet_link_status::new();
 
 	let res = ffi::knet_link_get_status(handle.knet_handle as ffi::knet_handle_t,
 					    host_id.host_id, link_id,
 					    &mut c_stats, size_of::<ffi::knet_link_status>());
 	(res, c_stats)
     };
     if res == 0 {
 	let r_status = LinkStatus::new(stats);
 	Ok(r_status)
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Get the logging subsystem ID given its name
 pub fn log_get_subsystem_id(name: &str) -> Result<u8>
 {
     let c_name = CString::new(name)?;
     let res = unsafe {
 	ffi::knet_log_get_subsystem_id(c_name.as_ptr())
     };
     Ok(res)
 }
 
 /// Get the logging subsystem name given its ID
 pub fn log_get_subsystem_name(id: u8) -> Result<String>
 {
     let res = unsafe {
 	ffi::knet_log_get_subsystem_name(id)
     };
     crate::string_from_bytes(res, 256)
 }
 
 /// Get the name of a logging level
 pub fn log_get_loglevel_id(name: &str) -> Result<u8>
 {
     let c_name = CString::new(name)?;
     let res = unsafe {
 	ffi::knet_log_get_loglevel_id(c_name.as_ptr())
     };
     Ok(res)
 }
 
 /// Get the ID of a logging level, given its name
 pub fn log_get_loglevel_name(id: u8) -> Result<String>
 {
     let res = unsafe {
 	ffi::knet_log_get_loglevel_name(id)
     };
     crate::string_from_bytes(res, 256)
 }
 
 /// Logging levels
 pub enum LogLevel {
     Err,
     Warn,
     Info,
     Debug,
     Trace,
 }
 impl LogLevel {
     pub fn new(level: u8) -> LogLevel {
 	match level {
 	    0 => LogLevel::Err,
 	    1 => LogLevel::Warn,
 	    2 => LogLevel::Info,
 	    3 => LogLevel::Debug,
 	    _ => LogLevel::Trace // 4=Trace, but default anything to it too
 	}
     }
     pub fn to_u8(self: &LogLevel) -> u8
     {
 	match self {
 	    LogLevel::Err => 0,
 	    LogLevel::Warn => 1,
 	    LogLevel::Info => 2,
 	    LogLevel::Debug => 3,
 	    LogLevel::Trace => 4,
 	}
     }
 }
 impl fmt::Display for LogLevel {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 	match self {
 	    LogLevel::Err => write!(f, "Err"),
 	    LogLevel::Warn => write!(f, "Warn"),
 	    LogLevel::Info => write!(f, "Info"),
 	    LogLevel::Debug => write!(f, "Debug"),
 	    LogLevel::Trace => write!(f, "Trace"),
 	}
     }
 }
 
 /// Subsystems known to the knet logger
 pub enum SubSystem
 {
     Common,
     Handle,
     Host,
     Listener,
     Link,
     Transport,
     Crypto,
     Compress,
 
     Filter,
 
     Dstcache,
     Heartbeat,
     Pmtud,
     Tx,
     Rx,
 
     TranspBase,
     TranspLoopback,
     TranspUdp,
     TranspSctp,
 
     NssCrypto,
     OpensslCrypto,
 
     Zlibcomp,
     Lz4comp,
     Lz4hccomp,
     Lzo2comp,
     Lzmacomp,
     Bzip2comp,
     Zstdcomp,
 
     Unknown,
 }
 impl SubSystem {
     pub fn to_u8(self: &SubSystem) -> u8
     {
 	match self {
 	    SubSystem::Common => ffi::KNET_SUB_COMMON,
 	    SubSystem::Handle => ffi::KNET_SUB_HANDLE,
 	    SubSystem::Host => ffi::KNET_SUB_HOST,
 	    SubSystem::Listener => ffi::KNET_SUB_LISTENER,
 	    SubSystem::Link => ffi::KNET_SUB_LINK,
 	    SubSystem::Transport => ffi::KNET_SUB_TRANSPORT,
 	    SubSystem::Crypto => ffi::KNET_SUB_CRYPTO,
 	    SubSystem::Compress => ffi::KNET_SUB_COMPRESS,
 	    SubSystem::Filter => ffi::KNET_SUB_FILTER,
 	    SubSystem::Dstcache => ffi::KNET_SUB_DSTCACHE,
 	    SubSystem::Heartbeat => ffi::KNET_SUB_HEARTBEAT,
 	    SubSystem::Pmtud => ffi::KNET_SUB_PMTUD,
 	    SubSystem::Tx => ffi::KNET_SUB_TX,
 	    SubSystem::Rx => ffi::KNET_SUB_RX,
 	    SubSystem::TranspBase => ffi::KNET_SUB_TRANSP_BASE,
 	    SubSystem::TranspLoopback => ffi::KNET_SUB_TRANSP_LOOPBACK,
 	    SubSystem::TranspUdp => ffi::KNET_SUB_TRANSP_UDP,
 	    SubSystem::TranspSctp => ffi::KNET_SUB_TRANSP_SCTP,
 	    SubSystem::NssCrypto => ffi::KNET_SUB_NSSCRYPTO,
 	    SubSystem::OpensslCrypto => ffi::KNET_SUB_OPENSSLCRYPTO,
 	    SubSystem::Zlibcomp => ffi::KNET_SUB_ZLIBCOMP,
 	    SubSystem::Lz4comp => ffi::KNET_SUB_LZ4COMP,
 	    SubSystem::Lz4hccomp => ffi::KNET_SUB_LZ4HCCOMP,
 	    SubSystem::Lzo2comp => ffi::KNET_SUB_LZO2COMP,
 	    SubSystem::Lzmacomp => ffi::KNET_SUB_LZMACOMP,
 	    SubSystem::Bzip2comp => ffi::KNET_SUB_BZIP2COMP,
 	    SubSystem::Zstdcomp => ffi::KNET_SUB_ZSTDCOMP,
 	    SubSystem::Unknown => ffi::KNET_SUB_UNKNOWN,
 	}
     }
     pub fn new(subsys: u8) -> SubSystem
     {
 	match subsys {
 	    1 => SubSystem::Unknown,
 	    2 => SubSystem::Unknown,
 	    _ => SubSystem::Unknown,
 	}
     }
 
 }
 
 /// Set the current logging level
-pub fn log_set_loglevel(handle: Handle, subsystem: SubSystem, level: LogLevel) -> Result<()>
+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>
+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 8a9d7ded..25ee40e9 100644
--- a/libknet/bindings/rust/tests/src/bin/knet-test.rs
+++ b/libknet/bindings/rust/tests/src/bin/knet-test.rs
@@ -1,979 +1,979 @@
 // 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 set_plugin_path(knet_h: u64);
 }
 
 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 {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 {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}");
 }
 
 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 ({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}");
 	    return Err(e);
 	}
     };
 
     // Make sure we use the build-tree plugins if LD_LIBRRAY_PATH points to them
     unsafe {
-	set_plugin_path(knet_handle);
+	set_plugin_path(knet_handle.knet_handle);
     }
 
-    if let Err(e) = knet::host_add(knet_handle, other_hostid) {
+    if let Err(e) = knet::host_add(&knet_handle, other_hostid) {
 	println!("Error from host_add: {e}");
 	return Err(e);
     }
-    if let Err(e) = knet::host_set_name(knet_handle, other_hostid, name) {
+    if let Err(e) = knet::host_set_name(&knet_handle, other_hostid, name) {
 	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,
+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}");
 		    return Err(e);
 		}
 		// In use - try the next port number
 	    }
 	} else {
 	    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>
+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}");
 		    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}");
 			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<()>
+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}");
 	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}");
 	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}");
 	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}");
 	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}");
 	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}");
 	return Err(e);
     }
     match knet::handle_add_datafd(knet_handle, 0, CHANNEL) {
 	Ok((fd,chan)) => {
 	    println!("Added datafd, fd={fd}, channel={chan}");
 	},
 	Err(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}");
 	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}");
 	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}");
 	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 {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}");
 	    return Err(e);
 	}
     }
 
     if let Err(e) = knet::handle_setfwd(knet_handle, true) {
 	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 {f} for channel");
 	    f
 	}
 	Err(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}");
 		return Err(Error::new(ErrorKind::Other, "Error in handle_get_channel"));
 	    }
 	Err(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}");
 	    return Err(e);
 	}
     }
 
     Ok(())
 }
 
-fn recv_stuff(handle: knet::Handle, host: knet::HostId) -> Result<()>
+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 {host}, exitting");
 			break;
 		    }
 		}
 	    }
 	    Err(e) => {
 		if e.kind() == ErrorKind::WouldBlock {
 		    thread::sleep(get_scaled_tmo(100));
 		} else {
 		    println!("recv failed: {e}");
 		    return Err(e);
 		}
 	    }
 	}
     }
     Ok(())
 }
 
 
-fn close_handle(handle: knet::Handle, remnode: u16) -> Result<()>
+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}");
 	return Err(e);
     }
 
     let data_fd =
     match knet::handle_get_datafd(handle, CHANNEL) {
 	Ok(f) => {
 	    println!("got datafd {f} for channel");
 	    f
 	}
 	Err(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}");
 	return Err(e);
     }
 
     if let Err(e) = knet::link_set_enable(handle, &other_hostid, 0, false) {
 	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}");
 	return Err(e);
     }
 
     if let Err(e) = knet::host_remove(handle, &other_hostid) {
 	println!("host remove failed: {e}");
 	return Err(e);
     }
 
     if let Err(e) = knet::handle_free(handle) {
 	println!("handle_free failed: {e}");
 	return Err(e);
     }
     Ok(())
 }
 
 
-fn set_compress(handle: knet::Handle) -> Result<()>
+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}");
 	Err(e)
     } else {
 	Ok(())
     }
 }
 
-fn set_crypto(handle: knet::Handle) -> Result<()>
+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}");
 	return Err(e);
     }
 
     if let Err(e) = knet::handle_crypto_use_config(handle, 1) {
 	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}");
 	return Err(e);
     }
     Ok(())
 }
 
 
-fn send_messages(handle: knet::Handle, send_quit: bool) -> Result<()>
+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}");
 		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}");
 	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}");
 		return Err(e);
 	    }
 	}
     }
     Ok(())
 }
 
-fn test_link_host_list(handle: knet::Handle) -> Result<()>
+fn test_link_host_list(handle: &knet::Handle) -> Result<()>
 {
     match knet::host_get_host_list(handle) {
 	Ok(hosts) => {
 	    for i in &hosts {
 		print!("host {i}: links: ");
 		match knet::link_get_link_list(handle, i) {
 		    Ok(ll) => {
 			for j in ll {
 			    print!(" {j}");
 			}
 		    },
 		    Err(e) => {
 			println!("link_get_link_list failed: {e}");
 			return Err(e);
 		    }
 		}
 		println!();
 	    }
 	}
 	Err(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<()>
+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:?}");
 	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}");
 	    }
 	},
 	Err(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:?}");
 	return Err(e);
     }
     match knet::handle_pmtud_get(handle) {
 	Ok(v) => {
 	    if v != 1000 {
 		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:?}");
 	    return Err(e);
 	}
     }
 
     if let Err(e) = knet::handle_pmtud_setfreq(handle, 1000) {
 	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}");
 	    }
 	},
 	Err(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:?}");
 	return Err(e);
     }
     match knet::handle_get_transport_reconnect_interval(handle) {
 	Ok(v) => {
 	    if v != 100 {
 		println!("knet_handle_get_transport_reconnect_interval {v}");
 	    }
 	},
 	Err(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:?}");
 	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}");
 	    }
 	},
 	Err(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:?}");
 	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}");
 	    }
 	},
 	Err(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:?}");
 	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}");
 	    }
 	},
 	Err(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}");
 	    n
 	},
 	Err(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}");
 	    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:?}");
 	    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:?}");
 	    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:?}");
 	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 {min},{max},{shrink},{policy}. expected 4,32,2,Absolute");
 		} else {
 		    println!("Defrag params correct: {min},{max},{shrink},{policy}");
 		}
 	}
 	Err(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:?}");
 	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}");
 	},
 	Err(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}"),
 	Err(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}"),
 	Err(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}"),
 	Err(e) => {
 	    println!("knet_log_get_loglevel_id failed: {e:?}");
 	    return Err(e);
 	}
     }
 
     match knet::log_get_loglevel_id("TRACE") {
 	Ok(n) => println!("loglevel ID for TRACE is {n}"),
 	Err(e) => {
 	    println!("knet_log_get_loglevel_id (Trace) failed: {e:?}");
 	    return Err(e);
 	}
     }
 
     match knet::log_get_loglevel_name(1) {
 	Ok(n) => println!("loglevel name for 1 is {n}"),
 	Err(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:?}");
 	return Err(e);
     }
     match knet::log_get_loglevel(handle, knet::SubSystem::Handle) {
 	Ok(n) => println!("loglevel for Handle is {n}"),
 	Err(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<()>
+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:?}");
 	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}");
 	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:?}");
 	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:?}");
 	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:?}");
 	return Err(e);
     }
     if let Err(e) = knet::link_clear_acl(handle, host, 1) {
 	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}");
 	return Err(e);
     }
 
     if let Err(e) = knet::handle_enable_access_lists(handle, false) {
 	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:?}");
 	    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:?}");
 	    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:?}");
 	    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)?;
+    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 handle1_clone = handle1.clone();
+    let handle2_clone = handle2.clone();
     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)?;
+    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))
+	spawn(move || recv_stuff(&handle1_clone, host1_clone)),
+	spawn(move || recv_stuff(&handle2_clone, host2_clone))
     ];
 
-    send_messages(handle1, false)?;
-    send_messages(handle2, false)?;
+    send_messages(&handle1, false)?;
+    send_messages(&handle2, false)?;
     thread::sleep(get_scaled_tmo(3000));
 
-    set_crypto(handle1)?;
-    set_crypto(handle2)?;
+    set_crypto(&handle1)?;
+    set_crypto(&handle2)?;
 
-    set_compress(handle1)?;
-    set_compress(handle2)?;
+    set_compress(&handle1)?;
+    set_compress(&handle2)?;
 
     thread::sleep(get_scaled_tmo(3000));
 
-    send_messages(handle1, true)?;
-    send_messages(handle2, true)?;
+    send_messages(&handle1, true)?;
+    send_messages(&handle2, true)?;
 
-    test_acl(handle1, &host2, low_port)?;
+    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:?}");
 	}
     }
 
     // Try some statses
-    match knet::handle_get_stats(handle1) {
+    match knet::handle_get_stats(&handle1) {
 	Ok(s) => println!("handle stats: {s}"),
 	Err(e) => {
 	    println!("handle_get_stats failed: {e:?}");
 	    return Err(e);
 	}
     }
-    match knet::host_get_status(handle1, &host2) {
+    match knet::host_get_status(&handle1, &host2) {
 	Ok(s) => println!("host status: {s}"),
 	Err(e) => {
 	    println!("host_get_status failed: {e:?}");
 	    return Err(e);
 	}
     }
-    match knet::link_get_status(handle1, &host2, 0) {
+    match knet::link_get_status(&handle1, &host2, 0) {
 	Ok(s) => println!("link status: {s}"),
 	Err(e) => {
 	    println!("link_get_status failed: {e:?}");
 	    return Err(e);
 	}
     }
-    if let Err(e) = knet::handle_clear_stats(handle1, knet::ClearStats::Handle) {
+    if let Err(e) = knet::handle_clear_stats(&handle1, knet::ClearStats::Handle) {
 	println!("handle_clear_stats failed: {e:?}");
 	return Err(e);
     }
 
-    test_metadata_calls(handle1, &knet::HostId::new(2))?;
+    test_metadata_calls(&handle1, &knet::HostId::new(2))?;
 
-    close_handle(handle1, 2)?;
-    close_handle(handle2, 1)?;
+    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/libknet/bindings/rust/tests/src/bin/set_plugin_path.c b/libknet/bindings/rust/tests/src/bin/set_plugin_path.c
index d4398300..90000e87 100644
--- a/libknet/bindings/rust/tests/src/bin/set_plugin_path.c
+++ b/libknet/bindings/rust/tests/src/bin/set_plugin_path.c
@@ -1,23 +1,23 @@
 /*
  * Copyright (C) 2021-2023 Red Hat, Inc.  All rights reserved.
  *
  * Author: Christine Caulfield <ccaulfie@redhat.com>
  *
  * This software licensed under GPL-2.0+
  */
 
 #include <stdio.h>
 
 #include "test-common.h"
 #include "internals.h"
 #include "libknet.h"
 
 // Set the path for compress/crypto plugins when running the test program
-void set_plugin_path(knet_handle_t knet_h)
+void set_plugin_path(knet_handle_t *knet_h)
 {
-	struct knet_handle *handle = (struct knet_handle *)knet_h;
 	char *plugins_path = find_plugins_path();
 	if (plugins_path) {
+		struct knet_handle *handle = (struct knet_handle *)knet_h;
 		handle->plugin_path = plugins_path;
 	}
 }
diff --git a/libnozzle/bindings/rust/src/nozzle_bindings.rs b/libnozzle/bindings/rust/src/nozzle_bindings.rs
index d3de7b65..79815f65 100644
--- a/libnozzle/bindings/rust/src/nozzle_bindings.rs
+++ b/libnozzle/bindings/rust/src/nozzle_bindings.rs
@@ -1,367 +1,389 @@
 // libnozzle interface for Rust
 // Copyright (C) 2021-2023 Red Hat, Inc.
 //
 // All rights reserved.
 //
 // Author: Christine Caulfield (ccaulfi@redhat.com)
 //
 
 
 // For the code generated by bindgen
 use crate::sys::libnozzle as ffi;
 
 use std::io::{Result, Error, ErrorKind};
 use std::os::raw::{c_char, c_void};
 use std::ptr::{null_mut};
 use libc::free;
 use std::fmt;
 
 /// A handle into the nozzle library. Returned from [open] and needed for all other calls
-#[derive(Copy, Clone, PartialEq, Eq)]
 pub struct Handle {
     nozzle_handle: ffi::nozzle_t,
+    clone: bool,
 }
 
+impl Clone for Handle {
+    fn clone(&self) -> Handle {
+	Handle {nozzle_handle: self.nozzle_handle, clone: true}
+    }
+}
+
+// Clones count as equivalent
+impl PartialEq for Handle {
+    fn eq(&self, other: &Handle) -> bool {
+	self.nozzle_handle == other.nozzle_handle
+    }
+}
+
+
 const IFNAMSZ: usize = 16;
 
 /// Create a new tap device on the system
 pub fn open(devname: &mut String, updownpath: &str) -> Result<Handle>
 {
     let mut c_devname: [c_char; IFNAMSZ] = [0; IFNAMSZ];
     let mut c_updownpath: [c_char; libc::PATH_MAX as usize] = [0; libc::PATH_MAX as usize];
     let c_devname_size = IFNAMSZ;
 
     crate::string_to_bytes(devname, &mut c_devname)?;
     crate::string_to_bytes(updownpath, &mut c_updownpath)?;
 
     let res = unsafe {
 	ffi::nozzle_open(c_devname.as_mut_ptr(), c_devname_size, c_updownpath.as_ptr())
     };
 
     if res.is_null() {
 	Err(Error::last_os_error())
     } else {
 	let temp = crate::string_from_bytes(c_devname.as_ptr(), IFNAMSZ)?;
 	*devname = temp;
-	Ok(Handle{nozzle_handle: res})
+	Ok(Handle{nozzle_handle: res, clone: false})
     }
 }
 
 /// Deconfigure and destroy a nozzle device
-pub fn close(handle: Handle) -> Result<()>
+pub fn close(handle: &Handle) -> Result<()>
 {
     let res = unsafe {
 	ffi::nozzle_close(handle.nozzle_handle)
     };
     if res == 0 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 }
 
+impl Drop for Handle {
+    fn drop(&mut self) {
+	if !self.clone {
+	    let _e = close(self);
+	}
+    }
+}
+
 /// Which script to run when [run_updown] is called
 pub enum Action {
     PreUp,
     Up,
     Down,
     PostDown
 }
 impl Action {
     pub fn to_u8(self: &Action) -> u8
     {
 	match self {
 	    Action::PreUp => 0,
 	    Action::Up => 1,
 	    Action::Down => 2,
 	    Action::PostDown => 3,
 	}
     }
 }
 
 /// Run an up/down script before/after configuring a device. See [Action]
-pub fn run_updown(handle: Handle, action: Action) -> Result<String>
+pub fn run_updown(handle: &Handle, action: Action) -> Result<String>
 {
     let c_exec_string : *mut *mut ::std::os::raw::c_char = &mut [0;0].as_mut_ptr();
     let c_action = action.to_u8();
 
     let res = unsafe {
 	ffi::nozzle_run_updown(handle.nozzle_handle, c_action, c_exec_string)
     };
 
     match res {
 	0 => {
 	    unsafe {
 		// This is unsafe because we deference a raw pointer
 		let resstring = crate::string_from_bytes(*c_exec_string as *mut ::std::os::raw::c_char, libc::PATH_MAX as usize)?;
 		free(*c_exec_string as *mut c_void);
 		Ok(resstring)
 	    }
 	},
 	-1 => Err(Error::last_os_error()),
 	-2 => Err(Error::new(ErrorKind::Other, "error executing shell scripts")),
 	_ => Err(Error::new(ErrorKind::Other, "unknown error returned from nozzle_tun_updown()")),
     }
 }
 
 /// Mark nozzle device as "up"
-pub fn set_up(handle: Handle) -> Result<()>
+pub fn set_up(handle: &Handle) -> Result<()>
 {
     let res = unsafe {
 	ffi::nozzle_set_up(handle.nozzle_handle)
     };
     if res == 0 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// mark nozzle device as "down"
-pub fn set_down(handle: Handle) -> Result<()>
+pub fn set_down(handle: &Handle) -> Result<()>
 {
     let res = unsafe {
 	ffi::nozzle_set_down(handle.nozzle_handle)
     };
     if res == 0 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 }
 const IPADDR_CHAR_MAX: usize = 128;
 const PREFIX_CHAR_MAX: usize = 4;
 
 /// Add an ip address to a nozzle device. multiple addresses can be added to one device.
 /// The prefix is a the number that comes after the ip address when configuring:
 /// eg: 192.168.0.1/24 - the prefix is "24"
-pub fn add_ip(handle: Handle, ipaddr: &str, prefix: &str) -> Result<()>
+pub fn add_ip(handle: &Handle, ipaddr: &str, prefix: &str) -> Result<()>
 {
     let mut c_ipaddr: [c_char; IPADDR_CHAR_MAX] = [0; IPADDR_CHAR_MAX];
     let mut c_prefix: [c_char; PREFIX_CHAR_MAX] = [0; PREFIX_CHAR_MAX];
 
     crate::string_to_bytes(ipaddr, &mut c_ipaddr)?;
     crate::string_to_bytes(prefix, &mut c_prefix)?;
     let res = unsafe {
 	ffi::nozzle_add_ip(handle.nozzle_handle, c_ipaddr.as_ptr(), c_prefix.as_ptr())
     };
     if res == 0 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 
 }
 
 /// remove an ip address from a nozzle device
-pub fn del_ip(handle: Handle, ipaddr: &str, prefix: &str) -> Result<()>
+pub fn del_ip(handle: &Handle, ipaddr: &str, prefix: &str) -> Result<()>
 {
     let mut c_ipaddr: [c_char; IPADDR_CHAR_MAX] = [0; IPADDR_CHAR_MAX];
     let mut c_prefix: [c_char; PREFIX_CHAR_MAX] = [0; PREFIX_CHAR_MAX];
 
     crate::string_to_bytes(ipaddr, &mut c_ipaddr)?;
     crate::string_to_bytes(prefix, &mut c_prefix)?;
     let res = unsafe {
 	ffi::nozzle_del_ip(handle.nozzle_handle, c_ipaddr.as_ptr(), c_prefix.as_ptr())
     };
     if res == 0 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// IpV4/IpV6 in the struct returned from [get_ips]
 pub enum Domain {
     IpV4,
     IpV6
 }
 impl Domain {
     fn new(c_dom: i32) -> Domain
     {
 	match c_dom {
 	    libc::AF_INET => Domain::IpV4,
 	    libc::AF_INET6 => Domain::IpV6,
 	    _ => Domain::IpV4,
 	}
     }
 }
 impl fmt::Display for Domain {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 	match self {
 	    Domain::IpV4 => write!(f, "IPv4"),
 	    Domain::IpV6 => write!(f, "IPv6"),
 	}
     }
 }
 
 /// IP address info as returned from [get_ips]
 pub struct Ip
 {
     pub ipaddr: String,
     pub prefix: String,
     pub domain: Domain,
 }
 impl Ip {
     pub fn new(c_ip: &ffi::nozzle_ip) -> Ip
     {
 	Ip {
 	    ipaddr: crate::string_from_bytes_safe(c_ip.ipaddr.as_ptr(), IPADDR_CHAR_MAX),
 	    prefix: crate::string_from_bytes_safe(c_ip.prefix.as_ptr(), PREFIX_CHAR_MAX),
 	    domain: Domain::new(c_ip.domain)
 	}
     }
 }
 impl fmt::Display for Ip {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 	write!(f,"{} {}/{}", self.domain, self.ipaddr, self.prefix)?;
 	Ok(())
     }
 }
 
 /// Return a Vec of Ip adressess attached to this device
-pub fn get_ips(handle: Handle) -> Result<Vec<Ip>>
+pub fn get_ips(handle: &Handle) -> Result<Vec<Ip>>
 {
     let mut c_ips : &mut ffi::nozzle_ip = &mut ffi::nozzle_ip{ipaddr: [0;129], prefix: [0;5], domain:0, next: null_mut()};
     let res = unsafe {
 	ffi::nozzle_get_ips(handle.nozzle_handle, &mut c_ips as *mut _ as *mut *mut ffi::nozzle_ip)
     };
     let mut ipvec = Vec::<Ip>::new();
     if res == 0 {
 	let mut ips : *mut ffi::nozzle_ip = c_ips;
 	unsafe {
 	    while !ips.is_null() {
 		ipvec.push(Ip::new(&*ips));
 		ips = (*ips).next;
 	    }
 	}
 	Ok(ipvec)
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Get the MTU of the device
-pub fn get_mtu(handle: Handle) -> Result<i32>
+pub fn get_mtu(handle: &Handle) -> Result<i32>
 {
     let res = unsafe {
 	ffi::nozzle_get_mtu(handle.nozzle_handle)
     };
     if res != -1 {
 	Ok(res)
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Set the MTU of the device
-pub fn set_mtu(handle: Handle, new_mtu: i32) -> Result<()>
+pub fn set_mtu(handle: &Handle, new_mtu: i32) -> Result<()>
 {
     let res = unsafe {
 	ffi::nozzle_set_mtu(handle.nozzle_handle, new_mtu)
     };
     if res != -1 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 
 /// Reset the device's MTU back to the default
-pub fn reset_mtu(handle: Handle) -> Result<()>
+pub fn reset_mtu(handle: &Handle) -> Result<()>
 {
     let res = unsafe {
 	ffi::nozzle_reset_mtu(handle.nozzle_handle)
     };
     if res != -1 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Returns the MAC address of the device
-pub fn get_mac(handle: Handle) -> Result<String>
+pub fn get_mac(handle: &Handle) -> Result<String>
 {
     let mut c_mac: *mut c_char = null_mut();
     let res = unsafe {
 	ffi::nozzle_get_mac(handle.nozzle_handle, &mut c_mac)
     };
     if res == 0 {
 	let mac = crate::string_from_bytes(c_mac, 24_usize)?; // Needs to be 8byte aligned
 	unsafe { free(c_mac as *mut c_void); }// Was created with strdup(
 	Ok(mac)
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Setsthe MAC address of the device
-pub fn set_mac(handle: Handle, ether_addr: &str) -> Result<()>
+pub fn set_mac(handle: &Handle, ether_addr: &str) -> Result<()>
 {
     let mut c_mac: [c_char; 24_usize] = [0; 24_usize]; // Needs to be 8byte aligned
     crate::string_to_bytes(ether_addr, &mut c_mac)?;
     let res = unsafe {
 	ffi::nozzle_set_mac(handle.nozzle_handle, c_mac.as_ptr())
     };
     if res == 0 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Reset the device's MAC address to the defaut
-pub fn reset_mac(handle: Handle) -> Result<()>
+pub fn reset_mac(handle: &Handle) -> Result<()>
 {
     let res = unsafe {
 	ffi::nozzle_reset_mac(handle.nozzle_handle)
     };
     if res == 0 {
 	Ok(())
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Find the nozzle handle of a device by giving its name
 pub fn get_handle_by_name(devname: &str) -> Result<Handle>
 {
     let mut c_devname: [c_char; IFNAMSZ] = [0; IFNAMSZ];
     crate::string_to_bytes(devname, &mut c_devname)?;
     let res = unsafe {
 	ffi::nozzle_get_handle_by_name(c_devname.as_ptr())
     };
     if !res.is_null() {
-	Ok(Handle{nozzle_handle:res})
+	Ok(Handle{nozzle_handle:res, clone: true})
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Return the name of the device
-pub fn get_name_by_handle(handle: Handle) -> Result<String>
+pub fn get_name_by_handle(handle: &Handle) -> Result<String>
 {
     let res = unsafe {
 	ffi::nozzle_get_name_by_handle(handle.nozzle_handle)
     };
     if !res.is_null() {
 	crate::string_from_bytes(res, IFNAMSZ)
     } else {
 	Err(Error::last_os_error())
     }
 }
 
 /// Return a unix FD for the device
-pub fn get_fd(handle: Handle) -> Result<i32>
+pub fn get_fd(handle: &Handle) -> Result<i32>
 {
     let res = unsafe {
 	ffi::nozzle_get_fd(handle.nozzle_handle)
     };
     if res != -1 {
 	Ok(res)
     } else {
 	Err(Error::last_os_error())
     }
 }
diff --git a/libnozzle/bindings/rust/tests/src/bin/nozzle-test.rs b/libnozzle/bindings/rust/tests/src/bin/nozzle-test.rs
index acd957c7..9079fc39 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}");
 	    h
 	},
 	Err(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) {
+    let saved_mtu = match nozzle::get_mtu(&handle) {
 	Ok(m) => m,
 	Err(e) => {
 	    println!("Error from get_mtu: {e}");
 	    return Err(e);
 	}
     };
-    let saved_mac = match nozzle::get_mac(handle) {
+    let saved_mac = match nozzle::get_mac(&handle) {
 	Ok(m) => m,
 	Err(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") {
+    if let Err(e) = nozzle::add_ip(&handle, "192.160.100.1", "24") {
 	println!("Error from add_ip: {e}");
 	return Err(e);
     }
-    if let Err(e) = nozzle::add_ip(handle, "192.160.100.2", "24") {
+    if let Err(e) = nozzle::add_ip(&handle, "192.160.100.2", "24") {
 	println!("Error from add_ip2: {e}");
 	return Err(e);
     }
-    if let Err(e) = nozzle::add_ip(handle, "192.160.100.3", "24") {
+    if let Err(e) = nozzle::add_ip(&handle, "192.160.100.3", "24") {
 	println!("Error from add_ip3: {e}");
 	return Err(e);
     }
 
-    if let Err(e) = nozzle::set_mac(handle, "AA:00:04:00:22:01") {
+    if let Err(e) = nozzle::set_mac(&handle, "AA:00:04:00:22:01") {
 	println!("Error from set_mac: {e}");
 	return Err(e);
     }
 
-    if let Err(e) = nozzle::set_mtu(handle, 157) {
+    if let Err(e) = nozzle::set_mtu(&handle, 157) {
 	println!("Error from set_mtu: {e}");
 	return Err(e);
     }
 
-    if let Err(e) = nozzle::set_up(handle) {
+    if let Err(e) = nozzle::set_up(&handle) {
 	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:?}");
 	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:?}");
 	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) {
+    match nozzle::run_updown(&handle, nozzle::Action::Up) {
 	Ok(s) => println!("Returned from Up script: {s}"),
 	Err(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) {
+    match nozzle::get_ips(&handle) {
 	Ok(ips) => {
 	    print!("Got IPs:");
 	    for i in ips {
 		print!(" {i}");
 	    }
 	    println!();
 	},
 	Err(e) => {
 	    println!("Error from get_ips: {e}");
 	    return Err(e);
 	}
     }
 
-    match nozzle::get_mtu(handle) {
+    match nozzle::get_mtu(&handle) {
 	Ok(m) => println!("Got mtu: {m}"),
 	Err(e) => {
-	    println!("Error from get_ips: {e}");
+	    println!("Error from get_mtu: {e}");
 	    return Err(e);
 	}
     }
-    match nozzle::get_mac(handle) {
+    match nozzle::get_mac(&handle) {
 	Ok(m) => println!("Got mac: {m}"),
 	Err(e) => {
-	    println!("Error from get_ips: {e}");
+	    println!("Error from get_mac: {e}");
 	    return Err(e);
 	}
     }
 
-    match nozzle::get_fd(handle) {
+    match nozzle::get_fd(&handle) {
 	Ok(f) => println!("Got FD: {f}"),
 	Err(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_handle_by_name: {e}");
 	    return Err(e);
 	}
     }
 
-    match nozzle::get_name_by_handle(handle) {
+    match nozzle::get_name_by_handle(&handle) {
 	Ok(n) => if 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_name_by_handle: {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") {
+    if let Err(e) = nozzle::del_ip(&handle, "192.160.100.3", "24") {
 	println!("Error from del_ip: {e}");
 	return Err(e);
     }
 
-    if let Err(e) = nozzle::reset_mtu(handle) {
+    if let Err(e) = nozzle::reset_mtu(&handle) {
 	println!("Error from reset_mtu: {e}");
 	return Err(e);
     }
-    match nozzle::get_mtu(handle) {
+    match nozzle::get_mtu(&handle) {
 	Ok(m) => {
 	    if m != saved_mtu {
 		println!("Got default MTU of {m}, not  {saved_mtu}");
 	    }
 	}
 	Err(e) => {
-	    println!("Error from get_ips: {e}");
+	    println!("Error from get_mtu: {e}");
 	    return Err(e);
 	}
     }
 
-    if let Err(e) = nozzle::reset_mac(handle) {
+    if let Err(e) = nozzle::reset_mac(&handle) {
 	println!("Error from reset_mac: {e}");
 	return Err(e);
     }
-    match nozzle::get_mac(handle) {
+    match nozzle::get_mac(&handle) {
 	Ok(m) => {
 	    if m != saved_mac {
 		println!("Got default MAC of {m}, not  {saved_mac}");
 	    }
 	}
 	Err(e) => {
-	    println!("Error from get_ips: {e}");
+	    println!("Error from get_mac: {e}");
 	    return Err(e);
 	}
     }
 
 
-    if let Err(e) = nozzle::set_down(handle){
+    if let Err(e) = nozzle::set_down(&handle){
 	println!("Error from set_down: {e}");
 	return Err(e);
     }
 
-    if let Err(e) = nozzle::close(handle) {
-	println!("Error from open: {e}");
+    if let Err(e) = nozzle::close(&handle) {
+	println!("Error from close: {e}");
 	return Err(e);
     }
     Ok(())
 }