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
//! Utilities related to FFI bindings

use crate::Result;
#[cfg(target_os = "linux")]
use libc::{c_char, in_addr, sockaddr_in};
use libc::{c_void, fd_set, suseconds_t, time_t, timeval};
use std::time::Duration;
use std::{mem, ptr};

pub mod c_str;

/// Helper trait to convert a raw `*mut c_void` to it's rust type
pub trait FromRaw<T> {
    /// Converts the specified `*mut c_void` to a `&'a mut T`.
    ///
    /// # Safety
    /// This function is unsafe due to the dereference of the specified raw pointer.
    unsafe fn from_raw<'a>(raw: *mut c_void) -> &'a mut T {
        assert_not_null!(raw);
        &mut *(raw as *mut T)
    }
}

/// Helper trait to convert and clone a raw `*mut c_void` to it's rust type
pub trait CloneRaw<T: FromRaw<T> + Clone> {
    /// Converts and clones the specified `*mut c_void` to a `Box<T>`.
    ///
    /// # Safety
    /// This function is unsafe due to a call to the unsafe function [`FromRaw::from_raw()`].
    ///
    /// [`FromRaw::from_raw()`]: trait.FromRaw.html#method.from_raw
    unsafe fn clone_raw(raw: *mut c_void) -> Box<T> {
        assert_not_null!(raw);
        Box::new(T::from_raw(raw).clone())
    }
}

/// Helper trait to convert self to a raw `*mut c_void`
pub trait AsRaw {
    /// Converts self to a raw `*mut c_void` by cast.
    fn as_raw(&mut self) -> *mut c_void {
        self as *mut _ as *mut c_void
    }
}

/// Performs a unix `select()` on the specified `sock_fd` and `timeout`. Returns the select result
/// or `Err` if the result is negative.
///
/// # Safety
/// This function is unsafe because it directly interfaces with C-library system calls.
pub unsafe fn read_select(sock_fd: i32, timeout: Duration) -> Result<u32> {
    let mut read_flags: fd_set = mem::zeroed();

    libc::FD_ZERO(&mut read_flags);
    libc::FD_SET(sock_fd, &mut read_flags);

    let tv_sec = timeout.as_secs() as time_t;
    let tv_usec = timeout.subsec_micros() as suseconds_t;
    let mut timeout = timeval { tv_sec, tv_usec };

    let result = libc::select(
        sock_fd + 1,
        &mut read_flags,
        ptr::null_mut(),
        ptr::null_mut(),
        &mut timeout,
    );

    if result < 0 {
        Err("select(): returned error status".into())
    } else {
        Ok(result as u32)
    }
}

/// Helper trait to unwrap a type to a `*const T` or a null-pointer if not present.
pub trait UnwrapOrNull<T> {
    /// Unwraps this type to `*const T` or `ptr::null()` if not present.
    fn unwrap_or_null(&self) -> *const T;
}

impl<T> UnwrapOrNull<T> for Option<*const T> {
    fn unwrap_or_null(&self) -> *const T {
        self.unwrap_or_else(|| ptr::null() as *const T)
    }
}

/// Helper trait to unwrap a type to a `*mut T` or a null-pointer if not present.
pub trait UnwrapMutOrNull<T> {
    /// Unwraps this type to `*mut T` or `ptr::null_mut()` if not present.
    fn unwrap_mut_or_null(&mut self) -> *mut T;
}

impl<T> UnwrapMutOrNull<T> for Option<*mut T> {
    fn unwrap_mut_or_null(&mut self) -> *mut T {
        self.unwrap_or_else(|| ptr::null_mut() as *mut T)
    }
}

/// Returns a human-readable address of the specified raw address
///
/// # Safety
/// This function is unsafe because of calls to C-library system calls
#[cfg(target_os = "linux")]
pub unsafe fn get_ip(address: *const sockaddr_in) -> String {
    assert_not_null!(address);
    let raw = inet_ntoa(&(*address).sin_addr as *const in_addr);
    String::from(c_str::raw_to_str(raw))
}

#[cfg(target_os = "linux")]
extern "C" {
    fn inet_ntoa(addr: *const in_addr) -> *const c_char;
}