use crate::raw::RawSocket;
#[cfg(unix)]
pub(crate) use unix::{wait_readable, wait_readable2, Waker};
#[cfg(windows)]
pub(crate) use windows::{wait_readable, wait_readable2, Waker};
#[cfg(unix)]
mod unix {
use super::RawSocket;
pub(crate) struct Waker(RawSocket);
impl Waker {
pub(crate) fn new() -> std::io::Result<Waker> {
let fd = unsafe { libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC) };
if fd < 0 {
return Err(std::io::Error::last_os_error());
}
Ok(Waker(fd))
}
pub(crate) fn wake(&self) {
let v: u64 = 1;
unsafe {
libc::write(self.0, (&v as *const u64).cast(), 8);
}
}
pub(crate) fn drain(&self) {
let mut v: u64 = 0;
while unsafe { libc::read(self.0, (&mut v as *mut u64).cast(), 8) } > 0 {}
}
pub(crate) fn raw(&self) -> RawSocket {
self.0
}
}
impl Drop for Waker {
fn drop(&mut self) {
unsafe {
libc::close(self.0);
}
}
}
pub(crate) fn wait_readable(fd: RawSocket, timeout_ms: u32) {
let mut pfd = libc::pollfd {
fd,
events: libc::POLLIN,
revents: 0,
};
unsafe {
libc::poll(&mut pfd, 1, timeout_ms as libc::c_int);
}
}
pub(crate) fn wait_readable2(a: RawSocket, b: RawSocket, timeout_ms: u32) {
let mut fds = [
libc::pollfd {
fd: a,
events: libc::POLLIN,
revents: 0,
},
libc::pollfd {
fd: b,
events: libc::POLLIN,
revents: 0,
},
];
unsafe {
libc::poll(fds.as_mut_ptr(), 2, timeout_ms as libc::c_int);
}
}
}
#[cfg(windows)]
mod windows {
use super::RawSocket;
use std::sync::Once;
const AF_INET: i32 = 2;
const SOCK_DGRAM: i32 = 2;
const FIONBIO: i32 = -2_147_195_266; const POLLRDNORM: i16 = 0x0100; const INVALID_SOCKET: usize = usize::MAX;
const WINSOCK_VERSION: u16 = 0x0202;
#[repr(C)]
struct WsaPollFd {
fd: usize,
events: i16,
revents: i16,
}
#[repr(C)]
struct SockaddrIn {
family: u16,
port: u16,
addr: u32,
zero: [u8; 8],
}
#[repr(C)]
struct WsaData {
_opaque: [u8; 408],
}
#[link(name = "ws2_32")]
extern "system" {
fn WSAStartup(version: u16, data: *mut WsaData) -> i32;
fn socket(af: i32, ty: i32, protocol: i32) -> usize;
fn bind(s: usize, addr: *const SockaddrIn, len: i32) -> i32;
fn connect(s: usize, addr: *const SockaddrIn, len: i32) -> i32;
fn getsockname(s: usize, addr: *mut SockaddrIn, len: *mut i32) -> i32;
fn ioctlsocket(s: usize, cmd: i32, argp: *mut u32) -> i32;
fn send(s: usize, buf: *const u8, len: i32, flags: i32) -> i32;
fn recv(s: usize, buf: *mut u8, len: i32, flags: i32) -> i32;
fn closesocket(s: usize) -> i32;
#[link_name = "WSAPoll"]
fn wsa_poll(fds: *mut WsaPollFd, nfds: u32, timeout: i32) -> i32;
}
fn ensure_winsock() {
static START: Once = Once::new();
START.call_once(|| {
let mut data = WsaData { _opaque: [0; 408] };
unsafe {
WSAStartup(WINSOCK_VERSION, &mut data);
}
});
}
pub(crate) struct Waker(usize);
impl Waker {
pub(crate) fn new() -> std::io::Result<Waker> {
ensure_winsock();
unsafe {
let s = socket(AF_INET, SOCK_DGRAM, 0);
if s == INVALID_SOCKET {
return Err(std::io::Error::last_os_error());
}
let mut addr = SockaddrIn {
family: AF_INET as u16,
port: 0, addr: u32::from_ne_bytes([127, 0, 0, 1]), zero: [0; 8],
};
let len = core::mem::size_of::<SockaddrIn>() as i32;
if bind(s, &addr, len) != 0 {
let e = std::io::Error::last_os_error();
closesocket(s);
return Err(e);
}
let mut got = len;
if getsockname(s, &mut addr, &mut got) != 0 || connect(s, &addr, len) != 0 {
let e = std::io::Error::last_os_error();
closesocket(s);
return Err(e);
}
let mut nonblocking: u32 = 1;
ioctlsocket(s, FIONBIO, &mut nonblocking);
Ok(Waker(s))
}
}
pub(crate) fn wake(&self) {
let b: u8 = 1;
unsafe {
send(self.0, &b, 1, 0);
}
}
pub(crate) fn drain(&self) {
let mut buf = [0u8; 64];
while unsafe { recv(self.0, buf.as_mut_ptr(), buf.len() as i32, 0) } > 0 {}
}
pub(crate) fn raw(&self) -> RawSocket {
self.0 as RawSocket
}
}
impl Drop for Waker {
fn drop(&mut self) {
unsafe {
closesocket(self.0);
}
}
}
pub(crate) fn wait_readable(fd: RawSocket, timeout_ms: u32) {
let mut pfd = WsaPollFd {
fd: fd as usize,
events: POLLRDNORM,
revents: 0,
};
unsafe {
wsa_poll(&mut pfd, 1, timeout_ms as i32);
}
}
pub(crate) fn wait_readable2(a: RawSocket, b: RawSocket, timeout_ms: u32) {
let mut fds = [
WsaPollFd {
fd: a as usize,
events: POLLRDNORM,
revents: 0,
},
WsaPollFd {
fd: b as usize,
events: POLLRDNORM,
revents: 0,
},
];
unsafe {
wsa_poll(fds.as_mut_ptr(), 2, timeout_ms as i32);
}
}
}