use std::future::Future;
use std::io;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::{AcquireError, OwnedSemaphorePermit, Semaphore};
use tonic::transport::server::{Connected, TcpConnectInfo};
type Acquiring = Pin<Box<dyn Future<Output = Result<OwnedSemaphorePermit, AcquireError>> + Send>>;
pub(super) struct BoundedIncoming {
listener: TcpListener,
limiter: Arc<Semaphore>,
permit: Option<OwnedSemaphorePermit>,
acquiring: Option<Acquiring>,
}
impl BoundedIncoming {
pub(super) fn new(listener: TcpListener, max_connections: Option<usize>) -> Self {
Self::counted(listener, max_connections).0
}
pub(super) fn counted(
listener: TcpListener,
max_connections: Option<usize>,
) -> (Self, OpenConnections) {
let capacity = max_connections.unwrap_or(Semaphore::MAX_PERMITS);
let limiter = Arc::new(Semaphore::new(capacity));
let open = OpenConnections {
limiter: Arc::clone(&limiter),
capacity,
};
let this = Self {
listener,
limiter,
permit: None,
acquiring: None,
};
(this, open)
}
}
pub(super) struct OpenConnections {
limiter: Arc<Semaphore>,
capacity: usize,
}
impl OpenConnections {
pub(super) fn count(&self) -> usize {
self.capacity - self.limiter.available_permits()
}
}
impl tokio_stream::Stream for BoundedIncoming {
type Item = io::Result<Permitted>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = &mut *self;
let permit = if let Some(permit) = this.permit.take() {
permit
} else {
let limiter = &this.limiter;
let acquiring = this
.acquiring
.get_or_insert_with(|| Box::pin(Arc::clone(limiter).acquire_owned()));
match acquiring.as_mut().poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(_closed)) => return Poll::Ready(None),
Poll::Ready(Ok(permit)) => {
this.acquiring = None;
permit
}
}
};
match this.listener.poll_accept(cx) {
Poll::Pending => {
this.permit = Some(permit);
Poll::Pending
}
Poll::Ready(Err(e)) => {
this.permit = Some(permit);
Poll::Ready(Some(Err(e)))
}
Poll::Ready(Ok((inner, _peer))) => Poll::Ready(Some(Ok(Permitted {
inner,
_permit: permit,
}))),
}
}
}
pub(super) struct Permitted<S = TcpStream> {
inner: S,
_permit: OwnedSemaphorePermit,
}
impl<S: AsyncRead + Unpin> AsyncRead for Permitted<S> {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_read(cx, buf)
}
}
impl<S: AsyncWrite + Unpin> AsyncWrite for Permitted<S> {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_write(cx, buf)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_flush(cx)
}
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_shutdown(cx)
}
fn poll_write_vectored(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[io::IoSlice<'_>],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.inner).poll_write_vectored(cx, bufs)
}
fn is_write_vectored(&self) -> bool {
self.inner.is_write_vectored()
}
}
impl Connected for Permitted<TcpStream> {
type ConnectInfo = TcpConnectInfo;
fn connect_info(&self) -> Self::ConnectInfo {
self.inner.connect_info()
}
}
#[cfg(test)]
mod tests {
use super::*;
use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
#[tokio::test]
async fn a_permitted_socket_writes_through_poll_write() {
let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind");
let addr = listener.local_addr().expect("addr");
let mut peer = TcpStream::connect(addr).await.expect("connect");
let (inner, _) = listener.accept().await.expect("accept");
drop(listener);
let mut permitted = Permitted {
inner,
_permit: Arc::new(Semaphore::new(1))
.acquire_owned()
.await
.expect("a fresh semaphore has a permit"),
};
permitted.write_all(b"hello").await.expect("write_all");
permitted.flush().await.expect("flush");
let mut buf = [0_u8; 5];
tokio::time::timeout(std::time::Duration::from_secs(5), peer.read_exact(&mut buf))
.await
.expect("the bytes arrive")
.expect("read_exact");
assert_eq!(&buf, b"hello");
permitted.shutdown().await.expect("shutdown");
let mut rest = Vec::new();
tokio::time::timeout(
std::time::Duration::from_secs(5),
peer.read_to_end(&mut rest),
)
.await
.expect("eof arrives")
.expect("eof after shutdown");
assert!(rest.is_empty(), "nothing follows the shutdown");
}
#[derive(Default)]
struct Recorder {
written: Vec<u8>,
vectored_calls: usize,
flushes: usize,
shutdowns: usize,
vectored: bool,
}
impl AsyncWrite for Recorder {
fn poll_write(
mut self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
self.written.extend_from_slice(buf);
Poll::Ready(Ok(buf.len()))
}
fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.flushes += 1;
Poll::Ready(Ok(()))
}
fn poll_shutdown(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.shutdowns += 1;
Poll::Ready(Ok(()))
}
fn poll_write_vectored(
mut self: Pin<&mut Self>,
_cx: &mut Context<'_>,
bufs: &[io::IoSlice<'_>],
) -> Poll<io::Result<usize>> {
self.vectored_calls += 1;
let mut n = 0;
for buf in bufs {
self.written.extend_from_slice(buf);
n += buf.len();
}
Poll::Ready(Ok(n))
}
fn is_write_vectored(&self) -> bool {
self.vectored
}
}
#[tokio::test]
async fn flush_shutdown_and_vectored_writes_are_forwarded() {
let permit = |limiter: &Arc<Semaphore>| {
Arc::clone(limiter)
.try_acquire_owned()
.expect("a fresh semaphore has a permit")
};
let limiter = Arc::new(Semaphore::new(2));
let mut permitted = Permitted {
inner: Recorder {
vectored: true,
..Recorder::default()
},
_permit: permit(&limiter),
};
assert!(permitted.is_write_vectored());
let bufs = [io::IoSlice::new(b"ab"), io::IoSlice::new(b"cd")];
let n = std::future::poll_fn(|cx| Pin::new(&mut permitted).poll_write_vectored(cx, &bufs))
.await
.expect("vectored write");
assert_eq!(n, 4);
permitted.flush().await.expect("flush");
permitted.shutdown().await.expect("shutdown");
assert_eq!(permitted.inner.written, b"abcd");
assert_eq!(permitted.inner.vectored_calls, 1);
assert_eq!(permitted.inner.flushes, 1);
assert_eq!(permitted.inner.shutdowns, 1);
drop(permitted);
assert!(
!Permitted {
inner: Recorder::default(),
_permit: permit(&limiter),
}
.is_write_vectored(),
"`is_write_vectored` follows the inner writer, not a constant"
);
}
}