#![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) -> io::Result<()> { unsafe { let mut readfds = { let mut readfds = mem::MaybeUninit::::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::::uninit(); libc::FD_ZERO(writefds.as_mut_ptr()); writefds.assume_init() }; let mut exceptfds = { let mut exceptfds = mem::MaybeUninit::::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 { 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) }