knet_bindings/
lib.rs

1// Copyright (C) 2021 Red Hat, Inc.  All rights reserved.
2//
3// Authors: Christine Caulfield <ccaulfie@redhat.com>
4//
5// This software licensed under LGPL-2.0+
6//
7
8//! This crate provides access to the kronosnet library 'libknet'
9//! from Rust. They are a fairly thin layer around the actual API calls but with Rust data types
10//! and iterators.
11//!
12//! No more information about knet itself will be provided here, it is expected that if
13//! you feel you need access to the knet API calls, you know what they do :)
14//!
15//! # Example
16//! ```
17//! use knet_bindings::knet_bindings as knet;
18//! use std::net::{SocketAddr, IpAddr, Ipv4Addr};
19//! use std::thread::spawn;
20//! use std::sync::mpsc::Receiver;
21//! use std::sync::mpsc::channel;
22//! use std::io::{Result, ErrorKind, Error};
23//! use std::{thread, time};
24//!
25//! const CHANNEL: i8 = 1;
26//!
27//! pub fn main() -> Result<()>
28//! {
29//!     let host_id = knet::HostId::new(1);
30//!     let other_host_id = knet::HostId::new(2);
31//!
32//!     let (log_sender, log_receiver) = channel::<knet::LogMsg>();
33//!     spawn(move || logging_thread(log_receiver));
34//!
35//!     let knet_handle = match knet::handle_new(&our_hostid, Some(log_sender),
36//!                                              knet::LogLevel::Debug, knet::HandleFlags::NONE) {
37//!         Ok(h) => h,
38//!         Err(e) => {
39//!             return Err(e);
40//!         }
41//!     };
42//!
43//!     if let Err(e) = knet::host_add(knet_handle, &other_hostid) {
44//!         return Err(e);
45//!     }
46//!     if let Err(e) = knet::link_set_config(knet_handle, &other_hostid, 0,
47//!                                 knet::TransportId::Udp,
48//!                                 &SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000+(our_hostid.to_u16())),
49//!                                 &SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000+(other_hostid.to_u16())),
50//!                                 knet::LinkFlags::NONE) {
51//!         return Err(e);
52//!     }
53//!     if let Err(e) = knet::handle_add_datafd(knet_handle, 0, CHANNEL) {
54//!         return Err(e);
55//!     }
56//!
57//!     if let Err(e) = knet::handle_crypto_rx_clear_traffic(knet_handle, knet::RxClearTraffic::Allow) {
58//!         return Err(e);
59//!     }
60//!
61//!     if let Err(e) = knet::link_set_enable(knet_handle, &other_hostid, 0, true) {
62//!         return Err(e);
63//!     }
64//!
65//!     if let Err(e) = knet::handle_setfwd(knet_handle, true) {
66//!         return Err(e);
67//!     }
68//!
69//!     Ok()
70//! }
71//!
72
73
74mod sys;
75pub mod knet_bindings;
76
77#[macro_use]
78extern crate lazy_static;
79#[macro_use]
80extern crate bitflags;
81
82use std::os::raw::c_char;
83use std::ptr::copy_nonoverlapping;
84use std::ffi::CString;
85use std::io::{Error, Result, ErrorKind};
86
87
88// Quick & dirty u8 to boolean
89fn u8_to_bool(val: u8) -> bool
90{
91    val != 0
92}
93
94fn u32_to_bool(val: u32) -> bool
95{
96    val != 0
97}
98
99// General internal routine to copy bytes from a C array into a Rust String
100fn string_from_bytes(bytes: *const ::std::os::raw::c_char, max_length: usize) -> Result<String>
101{
102    let mut newbytes = Vec::<u8>::new();
103    newbytes.resize(max_length, 0u8);
104
105    // Get length of the string in old-fashioned style
106    let mut length: usize = 0;
107    let mut count = 0;
108    let mut tmpbytes = bytes;
109    while count < max_length || length == 0 {
110	if unsafe {*tmpbytes} == 0 && length == 0 {
111	    length = count;
112	    break;
113	}
114	count += 1;
115	tmpbytes = unsafe { tmpbytes.offset(1) }
116    }
117
118    // Cope with an empty string
119    if length == 0 {
120	return Ok(String::new());
121    }
122
123    unsafe {
124	// We need to fully copy it, not shallow copy it.
125	// Messy casting on both parts of the copy here to get it to work on both signed
126	// and unsigned char machines
127	copy_nonoverlapping(bytes as *mut i8, newbytes.as_mut_ptr() as *mut i8, length);
128    }
129
130
131    let cs = CString::new(&newbytes[0..length as usize])?;
132
133    // This is just to convert the error type
134    match cs.into_string() {
135	Ok(s) => Ok(s),
136	Err(_) => Err(Error::new(ErrorKind::Other, "Cannot convert to String")),
137    }
138}
139
140// As below but always returns a string even if there was an error doing the conversion
141fn string_from_bytes_safe(bytes: *const ::std::os::raw::c_char, max_length: usize) -> String
142{
143    match string_from_bytes(bytes, max_length) {
144	Ok(s) => s,
145	Err(_)=> "".to_string()
146    }
147}
148
149fn string_to_bytes(s: &str, bytes: &mut [c_char]) -> Result<()>
150{
151    let c_name = match CString::new(s) {
152	Ok(n) => n,
153	Err(_) => return Err(Error::new(ErrorKind::Other, "Rust conversion error")),
154    };
155
156    if c_name.as_bytes().len() > bytes.len() {
157	return Err(Error::new(ErrorKind::Other, "String too long"));
158    }
159
160    unsafe {
161	// NOTE param order is 'wrong-way round' from C
162	copy_nonoverlapping(c_name.as_ptr(), bytes.as_mut_ptr(), c_name.as_bytes().len());
163    }
164    Ok(())
165}