1use std::time::Duration;
5
6pub trait Listener: Send + 'static {
8 type Io: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static;
10
11 type Addr: Clone + Send + Sync + 'static;
14
15 fn accept(&mut self) -> impl std::future::Future<Output = (Self::Io, Self::Addr)> + Send;
20
21 fn local_addr(&self) -> std::io::Result<Self::Addr>;
23}
24
25pub trait ListenerExt: Listener + Sized {
27 fn tap_io<F>(self, tap_fn: F) -> TapIo<Self, F>
47 where
48 F: FnMut(&mut Self::Io) + Send + 'static,
49 {
50 TapIo {
51 listener: self,
52 tap_fn,
53 }
54 }
55}
56
57impl<L: Listener> ListenerExt for L {}
58
59impl Listener for tokio::net::TcpListener {
60 type Io = tokio::net::TcpStream;
61 type Addr = std::net::SocketAddr;
62
63 async fn accept(&mut self) -> (Self::Io, Self::Addr) {
64 let mut backoff = AcceptBackoff::new();
65 loop {
66 match Self::accept(self).await {
67 Ok(tup) => return tup,
68 Err(e) => backoff.handle_accept_error(e).await,
69 }
70 }
71 }
72
73 #[inline]
74 fn local_addr(&self) -> std::io::Result<Self::Addr> {
75 Self::local_addr(self)
76 }
77}
78
79#[derive(Debug)]
80pub struct TcpListenerWithOptions {
81 inner: tokio::net::TcpListener,
82 nodelay: bool,
83 keepalive: Option<Duration>,
84}
85
86impl TcpListenerWithOptions {
87 pub fn new<A: std::net::ToSocketAddrs>(
88 addr: A,
89 nodelay: bool,
90 keepalive: Option<Duration>,
91 ) -> Result<Self, crate::BoxError> {
92 let mut last_error = None;
93 for addr in addr.to_socket_addrs()? {
94 match Self::bind(addr) {
95 Ok(listener) => return Ok(Self::from_listener(listener, nodelay, keepalive)),
96 Err(e) => last_error = Some(e),
97 }
98 }
99
100 Err(last_error
101 .unwrap_or_else(|| {
102 std::io::Error::new(
103 std::io::ErrorKind::InvalidInput,
104 "could not resolve to any address",
105 )
106 })
107 .into())
108 }
109
110 fn bind(addr: std::net::SocketAddr) -> std::io::Result<tokio::net::TcpListener> {
111 let socket = socket2::Socket::new(
112 socket2::Domain::for_address(addr),
113 socket2::Type::STREAM,
114 Some(socket2::Protocol::TCP),
115 )?;
116
117 #[cfg(not(windows))]
122 socket.set_reuse_address(true)?;
123 socket.set_nonblocking(true)?;
124 socket.bind(&addr.into())?;
125 socket.listen(1024)?;
126
127 tokio::net::TcpListener::from_std(socket.into())
128 }
129
130 pub fn from_listener(
132 listener: tokio::net::TcpListener,
133 nodelay: bool,
134 keepalive: Option<Duration>,
135 ) -> Self {
136 Self {
137 inner: listener,
138 nodelay,
139 keepalive,
140 }
141 }
142
143 fn set_accepted_socket_options(&self, stream: &tokio::net::TcpStream) {
145 if self.nodelay
146 && let Err(e) = stream.set_nodelay(true)
147 {
148 tracing::warn!("error trying to set TCP nodelay: {}", e);
149 }
150
151 if let Some(timeout) = self.keepalive {
152 let sock_ref = socket2::SockRef::from(&stream);
153 let sock_keepalive = socket2::TcpKeepalive::new().with_time(timeout);
154
155 if let Err(e) = sock_ref.set_tcp_keepalive(&sock_keepalive) {
156 tracing::warn!("error trying to set TCP keepalive: {}", e);
157 }
158 }
159 }
160}
161
162impl Listener for TcpListenerWithOptions {
163 type Io = tokio::net::TcpStream;
164 type Addr = std::net::SocketAddr;
165
166 async fn accept(&mut self) -> (Self::Io, Self::Addr) {
167 let (io, addr) = Listener::accept(&mut self.inner).await;
168 self.set_accepted_socket_options(&io);
169 (io, addr)
170 }
171
172 #[inline]
173 fn local_addr(&self) -> std::io::Result<Self::Addr> {
174 Listener::local_addr(&self.inner)
175 }
176}
177
178pub struct TapIo<L, F> {
203 listener: L,
204 tap_fn: F,
205}
206
207impl<L, F> std::fmt::Debug for TapIo<L, F>
208where
209 L: Listener + std::fmt::Debug,
210{
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 f.debug_struct("TapIo")
213 .field("listener", &self.listener)
214 .finish_non_exhaustive()
215 }
216}
217
218impl<L, F> Listener for TapIo<L, F>
219where
220 L: Listener,
221 F: FnMut(&mut L::Io) + Send + 'static,
222{
223 type Io = L::Io;
224 type Addr = L::Addr;
225
226 async fn accept(&mut self) -> (Self::Io, Self::Addr) {
227 let (mut io, addr) = self.listener.accept().await;
228 (self.tap_fn)(&mut io);
229 (io, addr)
230 }
231
232 fn local_addr(&self) -> std::io::Result<Self::Addr> {
233 self.listener.local_addr()
234 }
235}
236
237struct AcceptBackoff {
250 next_delay: Duration,
251}
252
253impl AcceptBackoff {
254 const MIN: Duration = Duration::from_millis(5);
255 const MAX: Duration = Duration::from_secs(1);
256
257 fn new() -> Self {
258 Self {
259 next_delay: Self::MIN,
260 }
261 }
262
263 async fn handle_accept_error(&mut self, e: std::io::Error) {
264 if is_connection_error(&e) {
265 return;
266 }
267
268 tracing::error!(backoff = ?self.next_delay, "accept error: {e}");
269 tokio::time::sleep(self.next_delay).await;
270 self.next_delay = (self.next_delay * 2).min(Self::MAX);
271 }
272}
273
274fn is_connection_error(e: &std::io::Error) -> bool {
275 use std::io::ErrorKind;
276
277 matches!(
278 e.kind(),
279 ErrorKind::ConnectionRefused
280 | ErrorKind::ConnectionAborted
281 | ErrorKind::ConnectionReset
282 | ErrorKind::BrokenPipe
283 | ErrorKind::Interrupted
284 | ErrorKind::WouldBlock
285 | ErrorKind::TimedOut
286 )
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[cfg(not(windows))]
298 #[tokio::test]
299 async fn listener_sets_reuse_address() {
300 let listener = TcpListenerWithOptions::new(("localhost", 0), true, None).unwrap();
301 let sock_ref = socket2::SockRef::from(&listener.inner);
302 assert!(sock_ref.reuse_address().unwrap());
303 }
304}