use std::fmt;
use std::future::Future;
use std::io;
use std::net::SocketAddr;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use std::sync::Arc;
use log::warn;
use tokio::time::Sleep;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use state::InitCell;
pub use tokio::net::TcpListener;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CertificateData(pub Vec<u8>);
impl AsRef<[u8]> for CertificateData {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
#[derive(Clone, Default)]
pub struct Certificates(Arc<InitCell<Vec<CertificateData>>>);
impl From<Vec<CertificateData>> for Certificates {
fn from(value: Vec<CertificateData>) -> Self {
Certificates(Arc::new(value.into()))
}
}
impl Certificates {
#[cfg(feature = "tls")]
pub(crate) fn set(&self, data: Vec<CertificateData>) {
self.0.set(data);
}
pub fn chain_data(&self) -> Option<&[CertificateData]> {
self.0.try_get().map(|v| v.as_slice())
}
}
pub trait Listener {
type Connection: Connection;
fn local_addr(&self) -> Option<SocketAddr>;
fn poll_accept(
self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<io::Result<Self::Connection>>;
}
pub trait Connection: AsyncRead + AsyncWrite {
fn peer_address(&self) -> Option<SocketAddr>;
fn enable_nodelay(&self) -> io::Result<()>;
fn peer_certificates(&self) -> Option<Certificates> { None }
}
pin_project_lite::pin_project! {
#[must_use = "streams do nothing unless polled"]
pub struct Incoming<L> {
sleep_on_errors: Option<Duration>,
nodelay: bool,
#[pin]
pending_error_delay: Option<Sleep>,
#[pin]
listener: L,
}
}
impl<L: Listener> Incoming<L> {
pub fn new(listener: L) -> Self {
Self {
listener,
sleep_on_errors: Some(Duration::from_millis(250)),
pending_error_delay: None,
nodelay: false,
}
}
pub fn sleep_on_errors(mut self, val: Option<Duration>) -> Self {
self.sleep_on_errors = val;
self
}
pub fn nodelay(mut self, nodelay: bool) -> Self {
self.nodelay = nodelay;
self
}
fn poll_accept_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<io::Result<L::Connection>> {
fn is_connection_error(e: &io::Error) -> bool {
matches!(e.kind(),
| io::ErrorKind::ConnectionRefused
| io::ErrorKind::ConnectionAborted
| io::ErrorKind::ConnectionReset)
}
let mut this = self.project();
loop {
if let Some(delay) = this.pending_error_delay.as_mut().as_pin_mut() {
futures::ready!(delay.poll(cx));
}
this.pending_error_delay.set(None);
match futures::ready!(this.listener.as_mut().poll_accept(cx)) {
Ok(stream) => {
if *this.nodelay {
if let Err(e) = stream.enable_nodelay() {
warn!("failed to enable NODELAY: {}", e);
}
}
return Poll::Ready(Ok(stream));
},
Err(e) => {
if is_connection_error(&e) {
warn!("single connection accept error {}; accepting next now", e);
} else if let Some(duration) = this.sleep_on_errors {
warn!("accept error {}; recovery attempt in {}ms", e, duration.as_millis());
this.pending_error_delay.set(Some(tokio::time::sleep(*duration)));
} else {
return Poll::Ready(Err(e));
}
},
}
}
}
}
impl<L: Listener> futures::Stream for Incoming<L> {
type Item = io::Result<L::Connection>;
#[inline]
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<Option<Self::Item>> {
self.poll_accept_next(cx).map(Some)
}
}
impl<L: fmt::Debug> fmt::Debug for Incoming<L> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Incoming")
.field("listener", &self.listener)
.finish()
}
}
impl Listener for TcpListener {
type Connection = TcpStream;
#[inline]
fn local_addr(&self) -> Option<SocketAddr> {
self.local_addr().ok()
}
#[inline]
fn poll_accept(
self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<io::Result<Self::Connection>> {
(*self).poll_accept(cx).map_ok(|(stream, _addr)| stream)
}
}
impl Connection for TcpStream {
#[inline]
fn peer_address(&self) -> Option<SocketAddr> {
self.peer_addr().ok()
}
#[inline]
fn enable_nodelay(&self) -> io::Result<()> {
self.set_nodelay(true)
}
}