use super::{AsyncAccept, AsyncListener, AsyncTls, Error, TlsListener};
use std::io;
use std::marker::Unpin;
use axum::serve::Listener;
use tokio::io::{AsyncRead, AsyncWrite};
use tracing::error;
#[cfg_attr(docsrs, doc(cfg(feature = "axum")))]
impl<A, T> Listener for TlsListener<A, T>
where
Self: Unpin + Send + 'static,
A: AsyncAccept<Error = std::io::Error> + AsyncListener,
A::Address: Send,
T: AsyncTls<A::Connection>,
T::Error: Send,
T::Stream: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
type Io = T::Stream;
type Addr = A::Address;
async fn accept(&mut self) -> (Self::Io, Self::Addr) {
loop {
match TlsListener::accept(self).await {
Ok(conn) => break conn,
Err(Error::ListenerError(e)) => handle_accept_error(e).await,
Err(e) => error!("TLS accept error: {}", e),
}
}
}
fn local_addr(&self) -> tokio::io::Result<Self::Addr> {
self.listener().local_addr()
}
}
async fn handle_accept_error(e: io::Error) {
if is_connection_error(&e) {
return;
}
error!("accept error: {e}");
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
fn is_connection_error(e: &io::Error) -> bool {
use std::io::ErrorKind::*;
matches!(
e.kind(),
ConnectionRefused | ConnectionAborted | ConnectionReset
)
}