1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright (C) 2021 Red Hat, Inc.  All rights reserved.
//
// Authors: Christine Caulfield <ccaulfie@redhat.com>
//
// This software licensed under LGPL-2.0+
//

//! This crate provides access to the kronosnet library 'libknet'
//! from Rust. They are a fairly thin layer around the actual API calls but with Rust data types
//! and iterators.
//!
//! No more information about knet itself will be provided here, it is expected that if
//! you feel you need access to the knet API calls, you know what they do :)
//!
//! # Example
//! ```
//! 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};
//!
//! const CHANNEL: i8 = 1;
//!
//! pub fn main() -> Result<()>
//! {
//!     let host_id = knet::HostId::new(1);
//!     let other_host_id = knet::HostId::new(2);
//!
//!     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) => {
//!             return Err(e);
//!         }
//!     };
//!
//!     if let Err(e) = knet::host_add(knet_handle, &other_hostid) {
//!         return Err(e);
//!     }
//!     if let Err(e) = knet::link_set_config(knet_handle, &other_hostid, 0,
//!                                 knet::TransportId::Udp,
//!                                 &SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000+(our_hostid.to_u16())),
//!                                 &SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000+(other_hostid.to_u16())),
//!                                 knet::LinkFlags::NONE) {
//!         return Err(e);
//!     }
//!     if let Err(e) = knet::handle_add_datafd(knet_handle, 0, CHANNEL) {
//!         return Err(e);
//!     }
//!
//!     if let Err(e) = knet::handle_crypto_rx_clear_traffic(knet_handle, knet::RxClearTraffic::Allow) {
//!         return Err(e);
//!     }
//!
//!     if let Err(e) = knet::link_set_enable(knet_handle, &other_hostid, 0, true) {
//!         return Err(e);
//!     }
//!
//!     if let Err(e) = knet::handle_setfwd(knet_handle, true) {
//!         return Err(e);
//!     }
//!
//!     Ok()
//! }
//!


mod sys;
pub mod knet_bindings;

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;

use std::os::raw::c_char;
use std::ptr::copy_nonoverlapping;
use std::ffi::CString;
use std::io::{Error, Result, ErrorKind};


// Quick & dirty u8 to boolean
fn u8_to_bool(val: u8) -> bool
{
    val != 0
}

fn u32_to_bool(val: u32) -> bool
{
    val != 0
}

// General internal routine to copy bytes from a C array into a Rust String
fn string_from_bytes(bytes: *const ::std::os::raw::c_char, max_length: usize) -> Result<String>
{
    let mut newbytes = Vec::<u8>::new();
    newbytes.resize(max_length, 0u8);

    // Get length of the string in old-fashioned style
    let mut length: usize = 0;
    let mut count = 0;
    let mut tmpbytes = bytes;
    while count < max_length || length == 0 {
	if unsafe {*tmpbytes} == 0 && length == 0 {
	    length = count;
	    break;
	}
	count += 1;
	tmpbytes = unsafe { tmpbytes.offset(1) }
    }

    // Cope with an empty string
    if length == 0 {
	return Ok(String::new());
    }

    unsafe {
	// We need to fully copy it, not shallow copy it.
	// Messy casting on both parts of the copy here to get it to work on both signed
	// and unsigned char machines
	copy_nonoverlapping(bytes as *mut i8, newbytes.as_mut_ptr() as *mut i8, length);
    }


    let cs = CString::new(&newbytes[0..length as usize])?;

    // This is just to convert the error type
    match cs.into_string() {
	Ok(s) => Ok(s),
	Err(_) => Err(Error::new(ErrorKind::Other, "Cannot convert to String")),
    }
}

// As below but always returns a string even if there was an error doing the conversion
fn string_from_bytes_safe(bytes: *const ::std::os::raw::c_char, max_length: usize) -> String
{
    match string_from_bytes(bytes, max_length) {
	Ok(s) => s,
	Err(_)=> "".to_string()
    }
}

fn string_to_bytes(s: &str, bytes: &mut [c_char]) -> Result<()>
{
    let c_name = match CString::new(s) {
	Ok(n) => n,
	Err(_) => return Err(Error::new(ErrorKind::Other, "Rust conversion error")),
    };

    if c_name.as_bytes().len() > bytes.len() {
	return Err(Error::new(ErrorKind::Other, "String too long"));
    }

    unsafe {
	// NOTE param order is 'wrong-way round' from C
	copy_nonoverlapping(c_name.as_ptr(), bytes.as_mut_ptr(), c_name.as_bytes().len());
    }
    Ok(())
}