use std::future::Future;
use std::io::Result;
use std::net::{SocketAddr, ToSocketAddrs};
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::{Duration, Instant};
use crate::each_addr;
use orengine_macros::{poll_for_io_request, poll_for_time_bounded_io_request};
use socket2::SockAddr;
use crate as orengine;
use crate::io::io_request_data::IoRequestData;
use crate::io::sys::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::io::worker::{local_worker, IoWorker};
pub struct Connect<'fut> {
fd: RawFd,
addr: &'fut SockAddr,
io_request_data: Option<IoRequestData>,
}
impl<'fut> Connect<'fut> {
pub fn new(fd: RawFd, addr: &'fut SockAddr) -> Self {
Self {
fd,
addr,
io_request_data: None,
}
}
}
impl Future for Connect<'_> {
type Output = Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
#[allow(unused, reason = "Cannot write proc_macro else to make it readable.")]
let ret;
poll_for_io_request!((
local_worker().connect(this.fd, this.addr.as_ptr(), this.addr.len(), unsafe {
this.io_request_data.as_mut().unwrap_unchecked()
}),
()
));
}
}
unsafe impl Send for Connect<'_> {}
pub struct ConnectWithDeadline<'fut> {
fd: RawFd,
addr: &'fut SockAddr,
io_request_data: Option<IoRequestData>,
deadline: Instant,
}
impl<'fut> ConnectWithDeadline<'fut> {
pub fn new(fd: RawFd, addr: &'fut SockAddr, deadline: Instant) -> Self {
Self {
fd,
addr,
io_request_data: None,
deadline,
}
}
}
impl Future for ConnectWithDeadline<'_> {
type Output = Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
let worker = local_worker();
#[allow(unused, reason = "Cannot write proc_macro else to make it readable.")]
let ret;
poll_for_time_bounded_io_request!((
worker.connect_with_deadline(
this.fd,
this.addr.as_ptr(),
this.addr.len(),
unsafe { this.io_request_data.as_mut().unwrap_unchecked() },
&mut this.deadline
),
()
));
}
}
unsafe impl Send for ConnectWithDeadline<'_> {}
pub trait AsyncConnectStream: Sized + AsRawFd {
async fn new_ip4() -> Result<Self>;
async fn new_ip6() -> Result<Self>;
#[inline(always)]
async fn new_for_addr(addr: &SocketAddr) -> Result<Self> {
match addr {
SocketAddr::V4(_) => Self::new_ip4().await,
SocketAddr::V6(_) => Self::new_ip6().await,
}
}
#[inline(always)]
async fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self> {
each_addr!(&addr, move |addr: SocketAddr| async move {
let stream = Self::new_for_addr(&addr).await?;
Connect::new(stream.as_raw_fd(), &SockAddr::from(addr)).await?;
Ok(stream)
})
}
#[inline(always)]
async fn connect_with_deadline<A: ToSocketAddrs>(addr: A, deadline: Instant) -> Result<Self> {
each_addr!(&addr, move |addr: SocketAddr| async move {
let stream = Self::new_for_addr(&addr).await?;
ConnectWithDeadline::new(stream.as_raw_fd(), &SockAddr::from(addr), deadline).await?;
Ok(stream)
})
}
#[inline(always)]
async fn connect_with_timeout<A: ToSocketAddrs>(addr: A, timeout: Duration) -> Result<Self> {
Self::connect_with_deadline(addr, Instant::now() + timeout).await
}
}
pub trait AsyncConnectDatagram<S: FromRawFd + Sized>: IntoRawFd + Sized {
#[inline(always)]
async fn connect<A: ToSocketAddrs>(self, addr: A) -> Result<S> {
let new_datagram_socket_fd = self.into_raw_fd();
each_addr!(&addr, move |addr: SocketAddr| async move {
Connect::new(new_datagram_socket_fd, &SockAddr::from(addr)).await?;
Ok(unsafe { S::from_raw_fd(new_datagram_socket_fd) })
})
}
#[inline(always)]
async fn connect_with_deadline<A: ToSocketAddrs>(
self,
addr: A,
deadline: Instant,
) -> Result<S> {
let new_datagram_socket_fd = self.into_raw_fd();
each_addr!(&addr, move |addr: SocketAddr| async move {
ConnectWithDeadline::new(new_datagram_socket_fd, &SockAddr::from(addr), deadline)
.await?;
Ok(unsafe { S::from_raw_fd(new_datagram_socket_fd) })
})
}
#[inline(always)]
async fn connect_with_timeout<A: ToSocketAddrs>(self, addr: A, timeout: Duration) -> Result<S> {
self.connect_with_deadline(addr, Instant::now() + timeout)
.await
}
}