renet/src/phy/sys/mod.rs

93 lines
3.0 KiB
Rust

#![allow(unsafe_code)]
use libc;
use std::{mem, ptr, io};
use std::os::unix::io::RawFd;
use crate::time::Duration;
#[cfg(target_os = "linux")]
#[path = "linux.rs"]
mod imp;
#[cfg(all(feature = "phy-raw_socket", target_os = "linux"))]
pub mod raw_socket;
#[cfg(all(feature = "phy-raw_socket", not(target_os = "linux"), unix))]
pub mod bpf;
#[cfg(all(feature = "phy-tap_interface", target_os = "linux"))]
pub mod tap_interface;
#[cfg(all(feature = "phy-raw_socket", target_os = "linux"))]
pub use self::raw_socket::RawSocketDesc;
#[cfg(all(feature = "phy-raw_socket", not(target_os = "linux"), unix))]
pub use self::bpf::BpfDevice as RawSocketDesc;
#[cfg(all(feature = "phy-tap_interface", target_os = "linux"))]
pub use self::tap_interface::TapInterfaceDesc;
/// Wait until given file descriptor becomes readable, but no longer than given timeout.
pub fn wait(fd: RawFd, duration: Option<Duration>) -> io::Result<()> {
unsafe {
let mut readfds = {
let mut readfds = mem::MaybeUninit::<libc::fd_set>::uninit();
libc::FD_ZERO(readfds.as_mut_ptr());
libc::FD_SET(fd, readfds.as_mut_ptr());
readfds.assume_init()
};
let mut writefds = {
let mut writefds = mem::MaybeUninit::<libc::fd_set>::uninit();
libc::FD_ZERO(writefds.as_mut_ptr());
writefds.assume_init()
};
let mut exceptfds = {
let mut exceptfds = mem::MaybeUninit::<libc::fd_set>::uninit();
libc::FD_ZERO(exceptfds.as_mut_ptr());
exceptfds.assume_init()
};
let mut timeout = libc::timeval { tv_sec: 0, tv_usec: 0 };
let timeout_ptr =
if let Some(duration) = duration {
timeout.tv_usec = (duration.total_millis() * 1_000) as libc::suseconds_t;
&mut timeout as *mut _
} else {
ptr::null_mut()
};
let res = libc::select(fd + 1, &mut readfds, &mut writefds, &mut exceptfds, timeout_ptr);
if res == -1 { return Err(io::Error::last_os_error()) }
Ok(())
}
}
#[cfg(all(any(feature = "phy-tap_interface", feature = "phy-raw_socket"), unix))]
#[repr(C)]
#[derive(Debug)]
struct ifreq {
ifr_name: [libc::c_char; libc::IF_NAMESIZE],
ifr_data: libc::c_int /* ifr_ifindex or ifr_mtu */
}
#[cfg(all(any(feature = "phy-tap_interface", feature = "phy-raw_socket"), unix))]
fn ifreq_for(name: &str) -> ifreq {
let mut ifreq = ifreq {
ifr_name: [0; libc::IF_NAMESIZE],
ifr_data: 0
};
for (i, byte) in name.as_bytes().iter().enumerate() {
ifreq.ifr_name[i] = *byte as libc::c_char
}
ifreq
}
#[cfg(all(target_os = "linux", any(feature = "phy-tap_interface", feature = "phy-raw_socket")))]
fn ifreq_ioctl(lower: libc::c_int, ifreq: &mut ifreq,
cmd: libc::c_ulong) -> io::Result<libc::c_int> {
unsafe {
let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq);
if res == -1 { return Err(io::Error::last_os_error()) }
}
Ok(ifreq.ifr_data)
}