#![allow(unsafe_code)]
use core::mem;
#[cfg(feature = "std")]
use std::{io, ptr};
#[cfg(feature = "std")]
use std::os::unix::io::RawFd;
use libc;
use crate::time::Instant;
#[cfg(feature = "std")]
use crate::time::Duration;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
mod raw_socket;
#[cfg(target_os = "linux")]
mod tap_interface;
pub mod exports {
#[cfg(target_os = "linux")]
pub use super::tap_interface::{TapInterface, TapInterfaceDesc};
#[cfg(target_os = "linux")]
pub use super::raw_socket::{RawSocket, RawSocketDesc};
#[cfg(feature = "std")]
pub use super::wait as sys_wait;
pub use super::Errno;
}
#[cfg(feature = "std")]
pub fn wait(fd: RawFd, duration: Option<Duration>) -> Result<(), Errno> {
let mut readfds;
unsafe {
let mut readfds_init = mem::MaybeUninit::<libc::fd_set>::uninit();
libc::FD_ZERO(readfds_init.as_mut_ptr());
libc::FD_SET(fd, readfds_init.as_mut_ptr());
readfds = readfds_init.assume_init();
}
let mut timeout = libc::timeval { tv_sec: 0, tv_usec: 0 };
let timeout = duration.map(|duration| {
timeout.tv_usec = duration.as_micros() as libc::suseconds_t;
&mut timeout
});
let timeout_ptr = timeout
.map(|reference| reference as *mut _)
.unwrap_or_else(ptr::null_mut);
let res = unsafe {
libc::select(
fd + 1,
&mut readfds,
ptr::null_mut(),
ptr::null_mut(),
timeout_ptr)
};
FdResult(res).errno()
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Errno(pub libc::c_int);
#[derive(Clone, Copy)]
struct FdResult(libc::c_int);
#[derive(Clone, Copy)]
struct IoLenResult(libc::ssize_t);
#[derive(Clone, Copy)]
struct ClockResult(libc::c_int);
type IoctlResult = FdResult;
#[allow(non_snake_case)] fn IoctlResult(val: libc::c_int) -> IoctlResult { FdResult(val) }
#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct ifreq {
ifr_name: [libc::c_char; libc::IF_NAMESIZE],
}
trait LibcResult: Copy {
fn is_fail(self) -> bool;
fn errno(self) -> Result<(), Errno> {
if self.is_fail() {
Err(Errno::new())
} else {
Ok(())
}
}
}
impl Errno {
pub fn new() -> Errno {
Errno(unsafe { *libc::__errno_location() })
}
}
impl LibcResult for FdResult {
fn is_fail(self) -> bool {
self.0 == -1
}
}
impl LibcResult for IoLenResult {
fn is_fail(self) -> bool {
self.0 == -1
}
}
impl LibcResult for ClockResult {
fn is_fail(self) -> bool {
self.0 == -1
}
}
#[cfg(feature = "std")]
impl From<Errno> for io::Error {
fn from(err: Errno) -> io::Error {
io::Error::from_raw_os_error(err.0 as i32)
}
}
impl ifreq {
fn new(name: &str) -> Self {
let mut ifr_name = [0; libc::IF_NAMESIZE];
for (i, byte) in name.as_bytes().iter().enumerate() {
ifr_name[i] = *byte as libc::c_char
}
ifreq {
ifr_name,
}
}
}
fn now() -> Result<Instant, Errno> {
let ts = unsafe {
let mut ts = mem::MaybeUninit::<libc::timespec>::uninit();
let res = libc::clock_gettime(libc::CLOCK_MONOTONIC, ts.as_mut_ptr());
ClockResult(res).errno()?;
ts.assume_init()
};
Ok(Instant::from_millis(ts.tv_sec*1000 + ts.tv_nsec/1000_000))
}