Skip to content

Commit

Permalink
feat(server): support wasm32-wasi
Browse files Browse the repository at this point in the history
Support the `wasm32-wasi` target, disabling unsupported components.

Signed-off-by: Richard Zak <[email protected]>
  • Loading branch information
rjzak committed Sep 30, 2022
1 parent 287d712 commit d9ed47e
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 13 deletions.
3 changes: 3 additions & 0 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[target.wasm32-wasi]
rustflags = ["--cfg", "tokio_unstable"]
runner = ["wasmtime", "run", "--"]
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down Expand Up @@ -100,7 +102,6 @@ runtime = [
"tokio/time",
]
tcp = [
"socket2",
"tokio/net",
"tokio/rt",
"tokio/time",
Expand Down
2 changes: 2 additions & 0 deletions src/server/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ impl Server<AddrIncoming, ()> {
///
/// 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<AddrIncoming> {
let incoming = AddrIncoming::new(addr).unwrap_or_else(|e| {
panic!("error binding to {}: {}", addr, e);
Expand All @@ -82,6 +83,7 @@ impl Server<AddrIncoming, ()> {
}

/// 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<Builder<AddrIncoming>> {
AddrIncoming::new(addr).map(Server::builder)
}
Expand Down
45 changes: 34 additions & 11 deletions src/server/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -78,6 +81,7 @@ pub struct AddrIncoming {
}

impl AddrIncoming {
#[cfg(not(target_os = "wasi"))]
pub(super) fn new(addr: &SocketAddr) -> crate::Result<Self> {
let std_listener = StdTcpListener::bind(addr).map_err(crate::Error::new_listen)?;

Expand All @@ -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<Self> {
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<Self> {
#[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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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()
Expand All @@ -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());
Expand All @@ -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();
Expand All @@ -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();
Expand Down

0 comments on commit d9ed47e

Please sign in to comment.