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 Jul 11, 2022
1 parent 0ff6213 commit cc8ab48
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 16 deletions.
17 changes: 11 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,22 @@ http = "0.2"
http-body = "0.4"
httpdate = "1.0"
httparse = "1.6"
h2 = { version = "0.3.9", optional = true }
# h2 = { version = "0.3.9", optional = true }
h2 = { git = "https://github.com/rjzak/h2", branch = "wasi_wip", optional = true }
itoa = "1"
tracing = { version = "0.1", default-features = false, features = ["std"] }
pin-project-lite = "0.2.4"
tower-service = "0.3"
tokio = { version = "1", features = ["sync"] }
# tokio = { version = "1", features = ["sync"] }
tokio = { git = "https://github.com/rjzak/tokio", branch = "wasi_wip", features = ["sync"] }
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 All @@ -49,7 +53,8 @@ pretty_env_logger = "0.4"
spmc = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = [
# tokio = { version = "1", features = [
tokio = { git = "https://github.com/rjzak/tokio", branch = "wasi_wip", features = [
"fs",
"macros",
"io-std",
Expand All @@ -61,7 +66,8 @@ tokio = { version = "1", features = [
"test-util",
] }
tokio-test = "0.4"
tokio-util = { version = "0.7", features = ["codec"] }
# tokio-util = { version = "0.7", features = ["codec"] }
tokio-util = { git = "https://github.com/rjzak/tokio", branch = "wasi_wip", features = ["codec"] }
tower = { version = "0.4", features = ["make", "util"] }
url = "2.2"

Expand Down Expand Up @@ -100,7 +106,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 @@ -72,6 +72,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 @@ -80,6 +81,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
42 changes: 32 additions & 10 deletions src/server/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use std::io;
use std::net::{SocketAddr, TcpListener as StdTcpListener};
use std::time::Duration;

#[cfg(target_os = "wasi")]
use std::net::{IpAddr, Ipv4Addr};

use tokio::net::TcpListener;
use tokio::time::Sleep;
use tracing::{debug, error, trace};
Expand All @@ -25,6 +28,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 @@ -41,13 +45,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 @@ -108,18 +120,26 @@ impl AddrIncoming {
loop {
match ready!(self.listener.poll_accept(cx)) {
Ok((socket, remote_addr)) => {
if let Some(dur) = self.tcp_keepalive_timeout {
let socket = socket2::SockRef::from(&socket);
let conf = socket2::TcpKeepalive::new().with_time(dur);
if let Err(e) = socket.set_tcp_keepalive(&conf) {
trace!("error trying to set TCP keepalive: {}", e);
#[cfg(not(target_os = "wasi"))]
{
if let Some(dur) = self.tcp_keepalive_timeout {
let socket = socket2::SockRef::from(&socket);
let conf = socket2::TcpKeepalive::new().with_time(dur);
if let Err(e) = socket.set_tcp_keepalive(&conf) {
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 @@ -199,6 +219,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 @@ -309,7 +331,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 Down

0 comments on commit cc8ab48

Please sign in to comment.