1use core::future::Future;
4use core::marker::Send;
5use core::net::SocketAddr;
6use core::pin::Pin;
7use core::time::Duration;
8#[cfg(feature = "__quic")]
9use std::sync::Arc;
10use std::time::{SystemTime, UNIX_EPOCH};
11use std::{
12 future::poll_fn,
13 io,
14 task::{Context, Poll},
15};
16
17use async_trait::async_trait;
18use futures_io::{AsyncRead, AsyncWrite};
19#[cfg(any(test, feature = "tokio"))]
20use tokio::runtime::Runtime;
21#[cfg(any(test, feature = "tokio"))]
22use tokio::task::JoinHandle;
23
24#[cfg(any(test, feature = "tokio"))]
26pub fn spawn_bg<F: Future<Output = R> + Send + 'static, R: Send + 'static>(
27 runtime: &Runtime,
28 background: F,
29) -> JoinHandle<R> {
30 runtime.spawn(background)
31}
32
33#[cfg(feature = "tokio")]
34#[doc(hidden)]
35pub mod iocompat {
36 use core::pin::Pin;
37 use core::task::{Context, Poll};
38 use std::io::{self, IoSlice};
39
40 use futures_io::{AsyncRead, AsyncWrite};
41 use tokio::io::{AsyncRead as TokioAsyncRead, AsyncWrite as TokioAsyncWrite, ReadBuf};
42
43 pub struct AsyncIoTokioAsStd<T: TokioAsyncRead + TokioAsyncWrite>(pub T);
45
46 impl<T: TokioAsyncRead + TokioAsyncWrite + Unpin> Unpin for AsyncIoTokioAsStd<T> {}
47 impl<R: TokioAsyncRead + TokioAsyncWrite + Unpin> AsyncRead for AsyncIoTokioAsStd<R> {
48 fn poll_read(
49 mut self: Pin<&mut Self>,
50 cx: &mut Context<'_>,
51 buf: &mut [u8],
52 ) -> Poll<io::Result<usize>> {
53 let mut buf = ReadBuf::new(buf);
54 let polled = Pin::new(&mut self.0).poll_read(cx, &mut buf);
55
56 polled.map_ok(|_| buf.filled().len())
57 }
58 }
59
60 impl<W: TokioAsyncRead + TokioAsyncWrite + Unpin> AsyncWrite for AsyncIoTokioAsStd<W> {
61 fn poll_write(
62 mut self: Pin<&mut Self>,
63 cx: &mut Context<'_>,
64 buf: &[u8],
65 ) -> Poll<io::Result<usize>> {
66 Pin::new(&mut self.0).poll_write(cx, buf)
67 }
68 fn poll_write_vectored(
69 mut self: Pin<&mut Self>,
70 cx: &mut Context<'_>,
71 bufs: &[IoSlice<'_>],
72 ) -> Poll<io::Result<usize>> {
73 Pin::new(&mut self.0).poll_write_vectored(cx, bufs)
74 }
75 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
76 Pin::new(&mut self.0).poll_flush(cx)
77 }
78 fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
79 Pin::new(&mut self.0).poll_shutdown(cx)
80 }
81 }
82
83 pub struct AsyncIoStdAsTokio<T: AsyncRead + AsyncWrite>(pub T);
85
86 impl<T: AsyncRead + AsyncWrite + Unpin> Unpin for AsyncIoStdAsTokio<T> {}
87 impl<R: AsyncRead + AsyncWrite + Unpin> TokioAsyncRead for AsyncIoStdAsTokio<R> {
88 fn poll_read(
89 self: Pin<&mut Self>,
90 cx: &mut Context<'_>,
91 buf: &mut ReadBuf<'_>,
92 ) -> Poll<io::Result<()>> {
93 Pin::new(&mut self.get_mut().0)
94 .poll_read(cx, buf.initialized_mut())
95 .map_ok(|len| buf.advance(len))
96 }
97 }
98
99 impl<W: AsyncRead + AsyncWrite + Unpin> TokioAsyncWrite for AsyncIoStdAsTokio<W> {
100 fn poll_write(
101 self: Pin<&mut Self>,
102 cx: &mut Context<'_>,
103 buf: &[u8],
104 ) -> Poll<Result<usize, io::Error>> {
105 Pin::new(&mut self.get_mut().0).poll_write(cx, buf)
106 }
107
108 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
109 Pin::new(&mut self.get_mut().0).poll_flush(cx)
110 }
111
112 fn poll_shutdown(
113 self: Pin<&mut Self>,
114 cx: &mut Context<'_>,
115 ) -> Poll<Result<(), io::Error>> {
116 Pin::new(&mut self.get_mut().0).poll_close(cx)
117 }
118 }
119}
120
121#[cfg(feature = "tokio")]
122#[allow(unreachable_pub)]
123mod tokio_runtime {
124 use std::sync::Arc;
125 use std::sync::Mutex;
126
127 #[cfg(feature = "__quic")]
128 use quinn::Runtime;
129 use tokio::net::{TcpSocket, TcpStream, UdpSocket as TokioUdpSocket};
130 use tokio::task::JoinSet;
131 use tokio::time::timeout;
132 use tracing::debug;
133
134 use super::iocompat::AsyncIoTokioAsStd;
135 use super::*;
136 use crate::xfer::CONNECT_TIMEOUT;
137
138 #[derive(Clone, Default)]
140 pub struct TokioHandle {
141 join_set: Arc<Mutex<JoinSet<()>>>,
142 }
143
144 impl Spawn for TokioHandle {
145 fn spawn_bg(&mut self, future: impl Future<Output = ()> + Send + 'static) {
146 let mut join_set = self.join_set.lock().unwrap();
147 join_set.spawn(future);
148 reap_tasks(&mut join_set);
149 }
150 }
151
152 #[derive(Clone, Default)]
154 pub struct TokioRuntimeProvider(TokioHandle);
155
156 impl TokioRuntimeProvider {
157 pub fn new() -> Self {
159 Self::default()
160 }
161 }
162
163 impl RuntimeProvider for TokioRuntimeProvider {
164 type Handle = TokioHandle;
165 type Timer = TokioTime;
166 type Udp = TokioUdpSocket;
167 type Tcp = AsyncIoTokioAsStd<TcpStream>;
168
169 fn create_handle(&self) -> Self::Handle {
170 self.0.clone()
171 }
172
173 fn connect_tcp(
174 &self,
175 server_addr: SocketAddr,
176 bind_addr: Option<SocketAddr>,
177 wait_for: Option<Duration>,
178 ) -> Pin<Box<dyn Send + Future<Output = Result<Self::Tcp, io::Error>>>> {
179 Box::pin(async move {
180 let socket = match server_addr {
181 SocketAddr::V4(_) => TcpSocket::new_v4(),
182 SocketAddr::V6(_) => TcpSocket::new_v6(),
183 }?;
184
185 if let Some(bind_addr) = bind_addr {
186 socket.bind(bind_addr)?;
187 }
188
189 socket.set_nodelay(true)?;
190 let future = socket.connect(server_addr);
191 let wait_for = wait_for.unwrap_or(CONNECT_TIMEOUT);
192 match timeout(wait_for, future).await {
193 Ok(Ok(socket)) => Ok(AsyncIoTokioAsStd(socket)),
194 Ok(Err(e)) => Err(e),
195 Err(_) => {
196 debug!(%server_addr, "TCP connect timeout");
197 Err(io::Error::new(
198 io::ErrorKind::TimedOut,
199 "TCP connect timed out",
200 ))
201 }
202 }
203 })
204 }
205
206 fn bind_udp(
207 &self,
208 local_addr: SocketAddr,
209 _server_addr: SocketAddr,
210 ) -> Pin<Box<dyn Send + Future<Output = Result<Self::Udp, io::Error>>>> {
211 Box::pin(async move { tokio::net::UdpSocket::bind(local_addr).await })
212 }
213
214 #[cfg(feature = "__quic")]
215 fn quic_binder(&self) -> Option<&dyn QuicSocketBinder> {
216 Some(&TokioQuicSocketBinder)
217 }
218 }
219
220 fn reap_tasks(join_set: &mut JoinSet<()>) {
222 while join_set.try_join_next().is_some() {}
223 }
224
225 #[cfg(feature = "__quic")]
226 struct TokioQuicSocketBinder;
227
228 #[cfg(feature = "__quic")]
229 impl QuicSocketBinder for TokioQuicSocketBinder {
230 fn bind_quic(
231 &self,
232 local_addr: SocketAddr,
233 _server_addr: SocketAddr,
234 ) -> Result<Arc<dyn quinn::AsyncUdpSocket>, io::Error> {
235 let socket = std::net::UdpSocket::bind(local_addr)?;
236 quinn::TokioRuntime.wrap_udp_socket(socket)
237 }
238 }
239}
240
241#[cfg(feature = "tokio")]
242pub use tokio_runtime::{TokioHandle, TokioRuntimeProvider};
243
244pub trait RuntimeProvider: Clone + Send + Sync + Unpin + 'static {
246 type Handle: Clone + Send + Spawn + Sync + Unpin;
248
249 type Timer: Time;
251
252 type Udp: DnsUdpSocket;
254
255 type Tcp: DnsTcpStream;
257
258 fn create_handle(&self) -> Self::Handle;
260
261 fn connect_tcp(
263 &self,
264 server_addr: SocketAddr,
265 bind_addr: Option<SocketAddr>,
266 timeout: Option<Duration>,
267 ) -> Pin<Box<dyn Send + Future<Output = Result<Self::Tcp, io::Error>>>>;
268
269 fn bind_udp(
272 &self,
273 local_addr: SocketAddr,
274 server_addr: SocketAddr,
275 ) -> Pin<Box<dyn Send + Future<Output = Result<Self::Udp, io::Error>>>>;
276
277 fn quic_binder(&self) -> Option<&dyn QuicSocketBinder> {
282 None
283 }
284}
285
286#[async_trait]
288pub trait DnsUdpSocket
289where
290 Self: Send + Sync + Sized + Unpin,
291{
292 type Time: Time;
294
295 fn poll_recv_from(
298 &self,
299 cx: &mut Context<'_>,
300 buf: &mut [u8],
301 ) -> Poll<io::Result<(usize, SocketAddr)>>;
302
303 async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
306 poll_fn(|cx| self.poll_recv_from(cx, buf)).await
307 }
308
309 fn poll_send_to(
311 &self,
312 cx: &mut Context<'_>,
313 buf: &[u8],
314 target: SocketAddr,
315 ) -> Poll<io::Result<usize>>;
316
317 async fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
319 poll_fn(|cx| self.poll_send_to(cx, buf, target)).await
320 }
321}
322
323#[cfg(not(feature = "__quic"))]
325pub trait QuicSocketBinder {}
326
327#[cfg(feature = "__quic")]
330pub trait QuicSocketBinder {
331 fn bind_quic(
333 &self,
334 _local_addr: SocketAddr,
335 _server_addr: SocketAddr,
336 ) -> Result<Arc<dyn quinn::AsyncUdpSocket>, io::Error>;
337}
338
339pub trait DnsTcpStream: AsyncRead + AsyncWrite + Unpin + Send + Sync + Sized + 'static {
341 type Time: Time;
343}
344
345pub trait Spawn {
347 fn spawn_bg(&mut self, future: impl Future<Output = ()> + Send + 'static);
349}
350
351#[async_trait]
354pub trait Time: Send + Sync + Unpin {
355 async fn delay_for(duration: Duration);
358
359 async fn timeout<F: 'static + Future + Send>(
361 duration: Duration,
362 future: F,
363 ) -> Result<F::Output, io::Error>;
364
365 fn current_time() -> u64 {
369 SystemTime::now()
370 .duration_since(UNIX_EPOCH)
371 .unwrap()
372 .as_secs()
373 }
374}
375
376#[cfg(any(test, feature = "tokio"))]
378#[derive(Clone, Copy, Debug)]
379pub struct TokioTime;
380
381#[cfg(any(test, feature = "tokio"))]
382#[async_trait]
383impl Time for TokioTime {
384 async fn delay_for(duration: Duration) {
385 tokio::time::sleep(duration).await
386 }
387
388 async fn timeout<F: 'static + Future + Send>(
389 duration: Duration,
390 future: F,
391 ) -> Result<F::Output, io::Error> {
392 tokio::time::timeout(duration, future)
393 .await
394 .map_err(move |_| io::Error::new(io::ErrorKind::TimedOut, "future timed out"))
395 }
396}