diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000000..2714d0f300 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,3 @@ +[target.wasm32-wasi] +rustflags = ["--cfg", "tokio_unstable"] +runner = ["wasmtime", "run", "--"] \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index dcfd3c3da9..6b15a337ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,9 @@ want = "0.3" # Optional libc = { version = "0.2", optional = true } -socket2 = { version = "0.4", optional = true } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +socket2 = { version = "0.4" } [dev-dependencies] futures-util = { version = "0.3", default-features = false, features = ["alloc"] } @@ -100,7 +102,6 @@ runtime = [ "tokio/time", ] tcp = [ - "socket2", "tokio/net", "tokio/rt", "tokio/time", diff --git a/src/server/server.rs b/src/server/server.rs index caa4aebd14..a64dcb810d 100644 --- a/src/server/server.rs +++ b/src/server/server.rs @@ -74,6 +74,7 @@ impl Server { /// /// This method will panic if binding to the address fails. For a method /// to bind to an address and return a `Result`, see `Server::try_bind`. + #[cfg(not(target_os = "wasi"))] pub fn bind(addr: &SocketAddr) -> Builder { let incoming = AddrIncoming::new(addr).unwrap_or_else(|e| { panic!("error binding to {}: {}", addr, e); @@ -82,6 +83,7 @@ impl Server { } /// Tries to bind to the provided address, and returns a [`Builder`](Builder). + #[cfg(not(target_os = "wasi"))] pub fn try_bind(addr: &SocketAddr) -> crate::Result> { AddrIncoming::new(addr).map(Server::builder) } diff --git a/src/server/tcp.rs b/src/server/tcp.rs index f475c09b1c..f1968cbe75 100644 --- a/src/server/tcp.rs +++ b/src/server/tcp.rs @@ -4,6 +4,9 @@ use std::net::{SocketAddr, TcpListener as StdTcpListener}; use std::time::Duration; use socket2::TcpKeepalive; +#[cfg(target_os = "wasi")] +use std::net::{IpAddr, Ipv4Addr}; + use tokio::net::TcpListener; use tokio::time::Sleep; use tracing::{debug, error, trace}; @@ -78,6 +81,7 @@ pub struct AddrIncoming { } impl AddrIncoming { + #[cfg(not(target_os = "wasi"))] pub(super) fn new(addr: &SocketAddr) -> crate::Result { let std_listener = StdTcpListener::bind(addr).map_err(crate::Error::new_listen)?; @@ -94,13 +98,21 @@ impl AddrIncoming { } /// Creates a new `AddrIncoming` binding to provided socket address. + #[cfg(not(target_os = "wasi"))] pub fn bind(addr: &SocketAddr) -> crate::Result { AddrIncoming::new(addr) } /// Creates a new `AddrIncoming` from an existing `tokio::net::TcpListener`. + /// For target `wasm32-wasi`, the assumed local address is "0.0.0.0:0", since + /// WebAssembly-Wasi has no way to know the local address used for listening. + /// This could be removed, but would require refactoring a lot of code in Hyper, + /// and other downstream projects. pub fn from_listener(listener: TcpListener) -> crate::Result { + #[cfg(not(target_os = "wasi"))] let addr = listener.local_addr().map_err(crate::Error::new_listen)?; + #[cfg(target_os = "wasi")] + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); Ok(AddrIncoming { listener, addr, @@ -172,17 +184,25 @@ impl AddrIncoming { loop { match ready!(self.listener.poll_accept(cx)) { Ok((socket, remote_addr)) => { - if let Some(tcp_keepalive) = &self.tcp_keepalive_config.into_socket2() { - let sock_ref = socket2::SockRef::from(&socket); - if let Err(e) = sock_ref.set_tcp_keepalive(tcp_keepalive) { - trace!("error trying to set TCP keepalive: {}", e); + #[cfg(not(target_os = "wasi"))] + { + if let Some(tcp_keepalive) = &self.tcp_keepalive_config.into_socket2() { + let sock_ref = socket2::SockRef::from(&socket); + if let Err(e) = sock_ref.set_tcp_keepalive(tcp_keepalive) { + trace!("error trying to set TCP keepalive: {}", e); + } + } + if let Err(e) = socket.set_nodelay(self.tcp_nodelay) { + trace!("error trying to set TCP nodelay: {}", e); } + let local_addr = socket.local_addr()?; + return Poll::Ready(Ok(AddrStream::new(socket, remote_addr, local_addr))); } - if let Err(e) = socket.set_nodelay(self.tcp_nodelay) { - trace!("error trying to set TCP nodelay: {}", e); + #[cfg(target_os = "wasi")] + { + let local_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0); + return Poll::Ready(Ok(AddrStream::new(socket, remote_addr, local_addr))); } - let local_addr = socket.local_addr()?; - return Poll::Ready(Ok(AddrStream::new(socket, remote_addr, local_addr))); } Err(e) => { // Connection errors can be ignored directly, continue by @@ -262,6 +282,8 @@ mod addr_stream { use std::net::SocketAddr; #[cfg(unix)] use std::os::unix::io::{AsRawFd, RawFd}; + #[cfg(target_os = "wasi")] + use std::os::wasi::io::{AsRawFd, RawFd}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio::net::TcpStream; @@ -372,7 +394,7 @@ mod addr_stream { } } - #[cfg(unix)] + #[cfg(any(unix, target_os = "wasi"))] impl AsRawFd for AddrStream { fn as_raw_fd(&self) -> RawFd { self.inner.as_raw_fd() @@ -385,6 +407,7 @@ mod tests { use std::time::Duration; use crate::server::tcp::TcpKeepaliveConfig; + #[cfg(not(target_os = "wasi"))] #[test] fn no_tcp_keepalive_config() { assert!(TcpKeepaliveConfig::default().into_socket2().is_none()); @@ -401,7 +424,7 @@ mod tests { } } - #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "solaris")))] + #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "solaris", target_os = "wasi")))] #[test] fn tcp_keepalive_interval_config() { let mut kac = TcpKeepaliveConfig::default(); @@ -413,7 +436,7 @@ mod tests { } } - #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "solaris", target_os = "windows")))] + #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "solaris", target_os = "windows", target_os = "wasi")))] #[test] fn tcp_keepalive_retries_config() { let mut kac = TcpKeepaliveConfig::default();