//! Re-exports of the async_std runtime for use with arti. //! //! This crate helps define a slim API around our async runtime so that we //! can easily swap it out. //! //! We'll probably want to support tokio as well in the future. /// Types used for networking (async_std implementation) mod net { use crate::network::{TcpConnectOptions, TcpListenOptions}; #[cfg(unix)] use crate::network::{UnixConnectOptions, UnixListenOptions}; use crate::{impls, traits}; use async_std_crate::net::{TcpListener, TcpStream, UdpSocket as StdUdpSocket}; #[cfg(unix)] use async_std_crate::os::unix::net::{UnixListener, UnixStream}; use async_trait::async_trait; use futures::stream::{self, Stream}; use paste::paste; use std::io::Result as IoResult; use std::net::SocketAddr; use std::pin::Pin; use std::task::{Context, Poll}; #[cfg(unix)] use tor_general_addr::unix; use tracing::instrument; /// Implement NetStreamProvider-related functionality for a single address type. macro_rules! impl_stream { { $kind:ident, $addr:ty } => {paste!{ /// A `Stream` of incoming streams. /// /// Differs from the output of `*Listener::incoming` in that this /// struct is a real type, and that it returns a stream and an address /// for each input. pub struct [] { /// Underlying stream of incoming connections. inner: Pin], $addr)>> + Send + Sync>>, } impl [] { /// Create a new IncomingStreams from a Listener. pub fn from_listener(lis: [<$kind Listener>]) -> [] { let stream = stream::unfold(lis, |lis| async move { let result = lis.accept().await; Some((result, lis)) }); Self { inner: Box::pin(stream), } } } impl Stream for [< Incoming $kind Streams >] { type Item = IoResult<([<$kind Stream>], $addr)>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.inner.as_mut().poll_next(cx) } } impl traits::NetStreamListener<$addr> for [<$kind Listener>] { type Stream = [<$kind Stream>]; type Incoming = []; fn incoming(self) -> [] { []::from_listener(self) } fn local_addr(&self) -> IoResult<$addr> { [<$kind Listener>]::local_addr(self) } } }} } impl_stream! { Tcp, std::net::SocketAddr } #[cfg(unix)] impl_stream! { Unix, unix::SocketAddr} #[async_trait] impl traits::NetStreamProvider for async_executors::AsyncStd { type Stream = TcpStream; type Listener = TcpListener; type ConnectOptions = TcpConnectOptions; type ListenOptions = TcpListenOptions; #[instrument(skip_all, level = "trace")] async fn connect( &self, addr: &SocketAddr, options: &Self::ConnectOptions, ) -> IoResult { // The async-std runtime uses async-io internally. let stream = impls::tcp_async_io_connect(addr, options).await?; Ok(stream.into()) } async fn listen( &self, addr: &SocketAddr, options: &Self::ListenOptions, ) -> IoResult { // Use an implementation that's the same across all runtimes. Ok(impls::tcp_listen(addr, options)?.into()) } } #[cfg(unix)] #[async_trait] impl traits::NetStreamProvider for async_executors::AsyncStd { type Stream = UnixStream; type Listener = UnixListener; type ConnectOptions = UnixConnectOptions; type ListenOptions = UnixListenOptions; #[instrument(skip_all, level = "trace")] async fn connect( &self, addr: &unix::SocketAddr, options: &Self::ConnectOptions, ) -> IoResult { // Will fail to compile if we add options without handling them here. let UnixConnectOptions {} = options; let path = addr .as_pathname() .ok_or(crate::unix::UnsupportedAfUnixAddressType)?; UnixStream::connect(path).await } async fn listen( &self, addr: &unix::SocketAddr, options: &Self::ListenOptions, ) -> IoResult { // Will fail to compile if we add options without handling them here. let UnixListenOptions {} = options; let path = addr .as_pathname() .ok_or(crate::unix::UnsupportedAfUnixAddressType)?; UnixListener::bind(path).await } } #[cfg(not(unix))] crate::impls::impl_unix_non_provider! { async_executors::AsyncStd } #[async_trait] impl traits::UdpProvider for async_executors::AsyncStd { type UdpSocket = UdpSocket; async fn bind(&self, addr: &std::net::SocketAddr) -> IoResult { StdUdpSocket::bind(*addr) .await .map(|socket| UdpSocket { socket }) } } /// Wrap a AsyncStd UdpSocket pub struct UdpSocket { /// The underlying UdpSocket socket: StdUdpSocket, } #[async_trait] impl traits::UdpSocket for UdpSocket { async fn recv(&self, buf: &mut [u8]) -> IoResult<(usize, SocketAddr)> { self.socket.recv_from(buf).await } async fn send(&self, buf: &[u8], target: &SocketAddr) -> IoResult { self.socket.send_to(buf, target).await } fn local_addr(&self) -> IoResult { self.socket.local_addr() } } impl traits::StreamOps for TcpStream { fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> { impls::streamops::set_tcp_notsent_lowat(self, notsent_lowat) } #[cfg(target_os = "linux")] fn new_handle(&self) -> Box { Box::new(impls::streamops::TcpSockFd::from_fd(self)) } } #[cfg(unix)] impl traits::StreamOps for UnixStream { fn set_tcp_notsent_lowat(&self, _notsent_lowat: u32) -> IoResult<()> { Err(traits::UnsupportedStreamOp::new( "set_tcp_notsent_lowat", "unsupported on Unix streams", ) .into()) } } } // ============================== use futures::{Future, FutureExt}; use std::pin::Pin; use std::time::Duration; use crate::traits::*; /// Create and return a new `async_std` runtime. pub fn create_runtime() -> async_executors::AsyncStd { async_executors::AsyncStd::new() } impl SleepProvider for async_executors::AsyncStd { type SleepFuture = Pin + Send + 'static>>; fn sleep(&self, duration: Duration) -> Self::SleepFuture { Box::pin(async_io::Timer::after(duration).map(|_| ())) } } impl ToplevelBlockOn for async_executors::AsyncStd { fn block_on(&self, f: F) -> F::Output { async_executors::AsyncStd::block_on(f) } } impl Blocking for async_executors::AsyncStd { type ThreadHandle = async_executors::BlockingHandle; fn spawn_blocking(&self, f: F) -> async_executors::BlockingHandle where F: FnOnce() -> T + Send + 'static, T: Send + 'static, { async_executors::SpawnBlocking::spawn_blocking(&self, f) } fn reenter_block_on(&self, f: F) -> F::Output { async_executors::AsyncStd::block_on(f) } }