use crate::event::{self, EndpointPublisher};
use core::task::{Context, Poll};
use s2n_quic_core::inet::SocketAddress;
use std::{collections::VecDeque, io, task::ready};
pub struct Queue<Stream> {
queue: VecDeque<(Stream, SocketAddress)>,
}
impl<Stream> Queue<Stream> {
#[inline]
pub fn new(capacity: usize) -> Self {
Self {
queue: VecDeque::with_capacity(capacity),
}
}
#[inline]
pub fn fill<L, Pub>(&mut self, cx: &mut Context, listener: &mut L, publisher: &Pub)
where
L: Listener<Stream = Stream>,
Pub: EndpointPublisher,
{
let mut remaining = self.queue.capacity() * 2;
let mut enqueued = 0;
let mut dropped = 0;
let mut errored = 0;
while let Poll::Ready(res) = listener.poll_accept(cx) {
match res {
Ok((socket, remote_address)) => {
if self.queue.len() == self.queue.capacity() {
if let Some(remote_address) = self
.queue
.pop_back()
.map(|(_socket, remote_address)| remote_address)
{
publisher.on_acceptor_tcp_stream_dropped(
event::builder::AcceptorTcpStreamDropped { remote_address: &remote_address, reason: event::builder::AcceptorTcpStreamDropReason::FreshQueueAtCapacity },
);
dropped += 1;
}
}
publisher.on_acceptor_tcp_fresh_enqueued(
event::builder::AcceptorTcpFreshEnqueued {
remote_address: &remote_address,
},
);
enqueued += 1;
self.queue.push_front((socket, remote_address));
}
Err(error) => {
publisher.on_acceptor_tcp_io_error(event::builder::AcceptorTcpIoError {
error: &error,
source: event::builder::AcceptorTcpIoErrorSource::Accept,
});
errored += 1;
}
}
remaining -= 1;
if remaining == 0 {
cx.waker().wake_by_ref();
break;
}
}
publisher.on_acceptor_tcp_fresh_batch_completed(
event::builder::AcceptorTcpFreshBatchCompleted {
enqueued,
dropped,
errored,
},
)
}
#[inline]
pub fn drain(&mut self) -> impl Iterator<Item = (Stream, SocketAddress)> + '_ {
self.queue.drain(..)
}
}
pub trait Listener {
type Stream;
fn poll_accept(&mut self, cx: &mut Context) -> Poll<io::Result<(Self::Stream, SocketAddress)>>;
}
impl Listener for tokio::io::unix::AsyncFd<std::net::TcpListener> {
type Stream = std::net::TcpStream;
#[inline]
fn poll_accept(&mut self, cx: &mut Context) -> Poll<io::Result<(Self::Stream, SocketAddress)>> {
loop {
let mut guard = ready!(self.poll_read_ready(cx))?;
let (socket, remote_addr) = match guard.try_io(|listener| listener.get_ref().accept()) {
Ok(v) => v?,
Err(_) => continue,
};
socket.set_nonblocking(true)?;
return Poll::Ready(Ok((socket, remote_addr.into())));
}
}
}