#[cfg(feature = "std")]
use std::io;
#[cfg(feature = "std")]
use core::future::Future;
#[cfg(feature = "std")]
use core::marker::PhantomData;
#[cfg(feature = "std")]
use core::net::SocketAddr;
#[cfg(feature = "std")]
use core::pin::Pin;
#[cfg(feature = "std")]
use core::task::{Context, Poll};
#[cfg(feature = "std")]
use futures::io::{AsyncRead, AsyncWrite};
#[cfg(feature = "alloc")]
pub use crate::pipe::endpoint::{BindAddr, PeerInfo};
#[cfg(feature = "std")]
mod datagram_batch_ext;
#[cfg(feature = "std")]
pub use datagram_batch_ext::DatagramSocketBatchExt;
pub const DEFAULT_LISTEN_BACKLOG: u32 = 1024;
#[cfg(feature = "std")]
pub trait StreamConnection: AsyncRead + AsyncWrite + Send + Unpin + 'static {
fn peer(&self) -> Option<PeerInfo>;
}
#[cfg(feature = "std")]
impl StreamConnection for Box<dyn StreamConnection> {
fn peer(&self) -> Option<PeerInfo> {
(**self).peer()
}
}
#[cfg(feature = "std")]
pub trait StreamListener: Send + Sync + 'static {
type Conn: StreamConnection;
fn poll_accept(&self, cx: &mut Context<'_>) -> Poll<io::Result<Self::Conn>>;
fn local_addr(&self) -> Option<BindAddr>;
}
#[cfg(feature = "std")]
pub type ConnectFuture<'lifetime, Connection> =
Pin<Box<dyn Future<Output = io::Result<Connection>> + Send + 'lifetime>>;
#[cfg(feature = "std")]
pub trait StreamUpstream: Send + Sync + 'static {
type Conn: StreamConnection;
fn connect_future(&self) -> ConnectFuture<'_, Self::Conn>;
}
#[cfg(feature = "std")]
pub trait StreamListenerExt: StreamListener {
fn accept(&self) -> Accept<'_, Self> {
Accept { listener: self }
}
}
#[cfg(feature = "std")]
impl<T: StreamListener + ?Sized> StreamListenerExt for T {}
#[cfg(feature = "std")]
pub trait StreamUpstreamExt: StreamUpstream {
fn connect(&self) -> Connect<'_, Self> {
Connect {
future: self.connect_future(),
upstream: PhantomData,
}
}
}
#[cfg(feature = "std")]
impl<T: StreamUpstream + ?Sized> StreamUpstreamExt for T {}
#[cfg(feature = "std")]
pub trait UnixUpstreamFactory: Send + Sync + 'static {
fn connect(
&self,
path: std::path::PathBuf,
) -> std::sync::Arc<dyn StreamUpstream<Conn = Box<dyn StreamConnection>>>;
}
#[cfg(feature = "std")]
pub struct Accept<'lifetime, L: StreamListener + ?Sized> {
listener: &'lifetime L,
}
#[cfg(feature = "std")]
impl<L: StreamListener + ?Sized> Future for Accept<'_, L> {
type Output = io::Result<L::Conn>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.listener.poll_accept(cx)
}
}
#[cfg(feature = "std")]
pub struct Connect<'lifetime, U: StreamUpstream + ?Sized> {
future: ConnectFuture<'lifetime, U::Conn>,
upstream: PhantomData<&'lifetime U>,
}
#[cfg(feature = "std")]
impl<U: StreamUpstream + ?Sized> Future for Connect<'_, U> {
type Output = io::Result<U::Conn>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.future.as_mut().poll(cx)
}
}
#[derive(Debug, Clone, Copy)]
pub struct TcpBindOptions {
pub backlog: u32,
pub reuseport: bool,
pub tcp_fastopen: Option<u32>,
}
impl Default for TcpBindOptions {
fn default() -> Self {
Self {
backlog: DEFAULT_LISTEN_BACKLOG,
reuseport: false,
tcp_fastopen: None,
}
}
}
#[cfg(feature = "std")]
pub trait TcpAcceptor: Send {
fn poll_accept(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<Box<dyn StreamConnection>>>;
fn local_addr(&self) -> io::Result<SocketAddr>;
}
#[cfg(feature = "std")]
pub trait AcceptorFactory: Send + Sync + 'static {
fn bind(&self, addr: SocketAddr, options: TcpBindOptions) -> io::Result<Box<dyn TcpAcceptor>>;
}
#[cfg(feature = "std")]
pub trait DatagramSocket: Send {
fn poll_recv_from(
&mut self,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<(usize, SocketAddr)>>;
fn poll_send_to(
&mut self,
cx: &mut Context<'_>,
buf: &[u8],
peer: SocketAddr,
) -> Poll<io::Result<usize>>;
fn poll_recv_batch(
&mut self,
cx: &mut Context<'_>,
bufs: &mut [&mut [u8]],
out_meta: &mut [(usize, SocketAddr)],
) -> Poll<io::Result<usize>> {
let want = bufs.len().min(out_meta.len());
let mut count = 0;
while count < want {
let slot: &mut [u8] = &mut *bufs[count];
match self.poll_recv_from(cx, slot) {
Poll::Ready(Ok((len, peer))) => {
out_meta[count] = (len, peer);
count += 1;
}
Poll::Ready(Err(_)) if count > 0 => return Poll::Ready(Ok(count)),
Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
Poll::Pending if count > 0 => return Poll::Ready(Ok(count)),
Poll::Pending => return Poll::Pending,
}
}
Poll::Ready(Ok(count))
}
fn poll_send_batch(
&mut self,
cx: &mut Context<'_>,
packets: &[(&[u8], SocketAddr)],
) -> Poll<io::Result<usize>> {
let mut sent = 0;
while sent < packets.len() {
let (bytes, peer) = packets[sent];
match self.poll_send_to(cx, bytes, peer) {
Poll::Ready(Ok(_)) => sent += 1,
Poll::Ready(Err(_)) if sent > 0 => return Poll::Ready(Ok(sent)),
Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
Poll::Pending if sent > 0 => return Poll::Ready(Ok(sent)),
Poll::Pending => return Poll::Pending,
}
}
Poll::Ready(Ok(sent))
}
fn local_addr(&self) -> io::Result<SocketAddr>;
}
#[cfg(feature = "std")]
pub trait DatagramFactory: Send + Sync + 'static {
fn bind(&self, addr: SocketAddr) -> io::Result<Box<dyn DatagramSocket>>;
fn backend_name(&self) -> &'static str {
"unknown"
}
}