use nix::libc;
use orengine_macros::{poll_for_io_request, poll_for_time_bounded_io_request};
use socket2::SockAddr;
use std::future::Future;
use std::io::Result;
use std::marker::PhantomData;
use std::mem;
use std::net::SocketAddr;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::{Duration, Instant};
use crate as orengine;
use crate::io::io_request_data::IoRequestData;
use crate::io::sys::{AsRawFd, FromRawFd, RawFd};
use crate::io::worker::{local_worker, IoWorker};
use crate::BUG_MESSAGE;
pub struct Accept<S: FromRawFd> {
fd: RawFd,
addr: (SockAddr, libc::socklen_t),
io_request_data: Option<IoRequestData>,
phantom_data: PhantomData<S>,
}
impl<S: FromRawFd> Accept<S> {
pub fn new(fd: RawFd) -> Self {
Self {
fd,
#[allow(
clippy::cast_possible_truncation,
reason = "size of SockAddr is less than u32::MAX"
)]
addr: (unsafe { mem::zeroed() }, size_of::<SockAddr>() as _),
io_request_data: None,
phantom_data: PhantomData,
}
}
}
impl<S: FromRawFd> Future for Accept<S> {
type Output = Result<(S, SockAddr)>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
let ret;
poll_for_io_request!((
local_worker().accept(
this.fd,
this.addr.0.as_ptr().cast_mut(),
&mut this.addr.1,
unsafe { this.io_request_data.as_mut().unwrap_unchecked() }
),
unsafe { (S::from_raw_fd(ret as RawFd), this.addr.0.clone()) }
));
}
}
unsafe impl<S: FromRawFd> Send for Accept<S> {}
pub struct AcceptWithDeadline<S: FromRawFd> {
fd: RawFd,
addr: (SockAddr, libc::socklen_t),
io_request_data: Option<IoRequestData>,
deadline: Instant,
pin: PhantomData<S>,
}
impl<S: FromRawFd> AcceptWithDeadline<S> {
pub fn new(fd: RawFd, deadline: Instant) -> Self {
Self {
fd,
#[allow(
clippy::cast_possible_truncation,
reason = "size of SockAddr is less than u32::MAX"
)]
addr: (unsafe { mem::zeroed() }, size_of::<SockAddr>() as _),
io_request_data: None,
deadline,
pin: PhantomData,
}
}
}
impl<S: FromRawFd> Future for AcceptWithDeadline<S> {
type Output = Result<(S, SockAddr)>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
let worker = local_worker();
let ret;
poll_for_time_bounded_io_request!((
worker.accept_with_deadline(
this.fd,
this.addr.0.as_ptr().cast_mut(),
&mut this.addr.1,
unsafe { this.io_request_data.as_mut().unwrap_unchecked() },
&mut this.deadline
),
unsafe { (S::from_raw_fd(ret as RawFd), this.addr.0.clone()) }
));
}
}
unsafe impl<S: FromRawFd> Send for AcceptWithDeadline<S> {}
pub trait AsyncAccept<S: FromRawFd>: AsRawFd {
#[inline(always)]
async fn accept(&mut self) -> Result<(S, SocketAddr)> {
let (stream, sock_addr) = Accept::<S>::new(self.as_raw_fd()).await?;
Ok((stream, sock_addr.as_socket().expect(BUG_MESSAGE)))
}
#[inline(always)]
async fn accept_with_deadline(&mut self, deadline: Instant) -> Result<(S, SocketAddr)> {
let (stream, sock_addr) = AcceptWithDeadline::<S>::new(self.as_raw_fd(), deadline).await?;
Ok((stream, sock_addr.as_socket().expect(BUG_MESSAGE)))
}
#[inline(always)]
async fn accept_with_timeout(&mut self, timeout: Duration) -> Result<(S, SocketAddr)> {
self.accept_with_deadline(Instant::now() + timeout).await
}
}