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
// 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 libraries libknet and libnozzle
//! 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 nozzle_bindings::nozzle_bindings as nozzle;
//! use std::io::{Result};
//! use std::env;
//! use std::{thread, time};
//!
//! fn main() -> Result<()>
//! {
//!     let mut nozzle_name = String::from("rustnoz");
//!     let handle = match nozzle::open(&mut nozzle_name,  &String::from(env::current_dir().unwrap().to_str().unwrap())) {
//!         Ok(h) => {
//!             println!("Opened device {}", nozzle_name);
//!             h
//!         },
//!         Err(e) => {
//!             println!("Error from open: {}", e);
//!             return Err(e);
//!         }
//!     };
//!
//!     let if Err(e) = nozzle::add_ip(handle, &"192.160.100.1".to_string(), &"24".to_string()) {
//!         println!("Error from add_ip: {}", e);
//!         return Err(e);
//!     }
//!
//!     let if Err(e) = nozzle::set_mtu(handle, 157) {
//!         println!("Error from set_mtu: {}", e);
//!         return Err(e);
//!     }
//!
//!     Ok(())
//! }


mod sys;
pub mod nozzle_bindings;

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

// 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(())
}