#[cfg(not(target_os = "windows"))]
extern crate libc;
#[cfg(not(target_os = "windows"))]
use libc::{time_t, c_long, POLLIN, timespec, pollfd, ppoll};
#[cfg(not(target_os = "windows"))]
use std::os::fd::AsRawFd;
#[cfg(not(target_os = "windows"))]
use std::ptr;
#[cfg(target_os = "windows")]
extern crate windows_sys;
#[cfg(target_os = "windows")]
use windows_sys::Win32::Networking::WinSock::{POLLIN, WSAPOLLFD as pollfd, WSAPoll as poll};
#[cfg(target_os = "windows")]
use std::os::windows::io::AsRawSocket;
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::io::Result as IoResult;
use std::time::Duration;
pub trait TcpListenerAcceptTimeout {
fn accept_timeout(&self, timeout: Option<Duration>) -> Option<IoResult<(TcpStream, SocketAddr)>>;
fn connection_pending(&self, timeout: Option<Duration>) -> bool;
}
impl TcpListenerAcceptTimeout for TcpListener {
fn accept_timeout(&self, timeout: Option<Duration>) -> Option<IoResult<(TcpStream, SocketAddr)>> {
if !self.connection_pending(timeout) {
return None;
}
Some(self.accept())
}
#[cfg(not(target_os = "windows"))]
fn connection_pending(&self, timeout: Option<Duration>) -> bool {
let mut fd = pollfd {
fd: self.as_raw_fd(),
events: POLLIN,
revents: 0,
};
unsafe {
ppoll(&mut fd,
1,
timeout.map(|timeout| {
timespec {
tv_sec: timeout.as_secs() as time_t,
tv_nsec: timeout.subsec_nanos() as c_long,
}
})
.as_ref()
.map(|timeout| timeout as *const _)
.unwrap_or(ptr::null()),
ptr::null()) == 1 && (fd.revents & POLLIN) != 0
}
}
#[cfg(target_os = "windows")]
fn connection_pending(&self, timeout: Option<Duration>) -> bool {
let mut fd = pollfd {
fd: self.as_raw_socket() as usize,
events: POLLIN,
revents: 0,
};
unsafe {
match timeout {
None => poll(&mut fd, 1, -1) == 1 && (fd.revents & POLLIN) != 0,
Some(timeout) => {
let mut ms = timeout.as_millis();
while ms > i32::MAX as u128 {
let ret = poll(&mut fd, 1, i32::MAX);
if ret != 0 {
return ret == 1 && (fd.revents & POLLIN) != 0;
}
ms -= i32::MAX as u128;
}
poll(&mut fd, 1, ms as i32) == 1 && (fd.revents & POLLIN) != 0
}
}
}
}
}