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}