Skip to content

Commit 4fdbbdc

Browse files
committed
feat(server): support wasm32-wasi
Support the `wasm32-wasi` target, disabling unsupported components. Signed-off-by: Richard Zak <[email protected]>
1 parent 287d712 commit 4fdbbdc

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ want = "0.3"
3939
# Optional
4040

4141
libc = { version = "0.2", optional = true }
42-
socket2 = { version = "0.4", optional = true }
42+
43+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
44+
socket2 = { version = "0.4" }
4345

4446
[dev-dependencies]
4547
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
@@ -100,7 +102,6 @@ runtime = [
100102
"tokio/time",
101103
]
102104
tcp = [
103-
"socket2",
104105
"tokio/net",
105106
"tokio/rt",
106107
"tokio/time",

src/server/server.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ impl Server<AddrIncoming, ()> {
7474
///
7575
/// This method will panic if binding to the address fails. For a method
7676
/// to bind to an address and return a `Result`, see `Server::try_bind`.
77+
#[cfg(not(target_os = "wasi"))]
7778
pub fn bind(addr: &SocketAddr) -> Builder<AddrIncoming> {
7879
let incoming = AddrIncoming::new(addr).unwrap_or_else(|e| {
7980
panic!("error binding to {}: {}", addr, e);
@@ -82,6 +83,7 @@ impl Server<AddrIncoming, ()> {
8283
}
8384

8485
/// Tries to bind to the provided address, and returns a [`Builder`](Builder).
86+
#[cfg(not(target_os = "wasi"))]
8587
pub fn try_bind(addr: &SocketAddr) -> crate::Result<Builder<AddrIncoming>> {
8688
AddrIncoming::new(addr).map(Server::builder)
8789
}

src/server/tcp.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use std::net::{SocketAddr, TcpListener as StdTcpListener};
44
use std::time::Duration;
55
use socket2::TcpKeepalive;
66

7+
#[cfg(target_os = "wasi")]
8+
use std::net::{IpAddr, Ipv4Addr};
9+
710
use tokio::net::TcpListener;
811
use tokio::time::Sleep;
912
use tracing::{debug, error, trace};
@@ -78,6 +81,7 @@ pub struct AddrIncoming {
7881
}
7982

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

@@ -94,13 +98,21 @@ impl AddrIncoming {
9498
}
9599

96100
/// Creates a new `AddrIncoming` binding to provided socket address.
101+
#[cfg(not(target_os = "wasi"))]
97102
pub fn bind(addr: &SocketAddr) -> crate::Result<Self> {
98103
AddrIncoming::new(addr)
99104
}
100105

101106
/// Creates a new `AddrIncoming` from an existing `tokio::net::TcpListener`.
107+
/// For target `wasm32-wasi`, the assumed local address is "0.0.0.0:0", since
108+
/// WebAssembly-Wasi has no way to know the local address used for listening.
109+
/// This could be removed, but would require refactoring a lot of code in Hyper,
110+
/// and other downstream projects.
102111
pub fn from_listener(listener: TcpListener) -> crate::Result<Self> {
112+
#[cfg(not(target_os = "wasi"))]
103113
let addr = listener.local_addr().map_err(crate::Error::new_listen)?;
114+
#[cfg(target_os = "wasi")]
115+
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0);
104116
Ok(AddrIncoming {
105117
listener,
106118
addr,
@@ -172,17 +184,26 @@ impl AddrIncoming {
172184
loop {
173185
match ready!(self.listener.poll_accept(cx)) {
174186
Ok((socket, remote_addr)) => {
175-
if let Some(tcp_keepalive) = &self.tcp_keepalive_config.into_socket2() {
176-
let sock_ref = socket2::SockRef::from(&socket);
177-
if let Err(e) = sock_ref.set_tcp_keepalive(tcp_keepalive) {
178-
trace!("error trying to set TCP keepalive: {}", e);
187+
#[cfg(not(target_os = "wasi"))]
188+
{
189+
if let Some(dur) = self.tcp_keepalive_timeout {
190+
let socket = socket2::SockRef::from(&socket);
191+
let conf = socket2::TcpKeepalive::new().with_time(dur);
192+
if let Err(e) = socket.set_tcp_keepalive(&conf) {
193+
trace!("error trying to set TCP keepalive: {}", e);
194+
}
179195
}
196+
if let Err(e) = socket.set_nodelay(self.tcp_nodelay) {
197+
trace!("error trying to set TCP nodelay: {}", e);
198+
}
199+
let local_addr = socket.local_addr()?;
200+
return Poll::Ready(Ok(AddrStream::new(socket, remote_addr, local_addr)));
180201
}
181-
if let Err(e) = socket.set_nodelay(self.tcp_nodelay) {
182-
trace!("error trying to set TCP nodelay: {}", e);
202+
#[cfg(target_os = "wasi")]
203+
{
204+
let local_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0);
205+
return Poll::Ready(Ok(AddrStream::new(socket, remote_addr, local_addr)));
183206
}
184-
let local_addr = socket.local_addr()?;
185-
return Poll::Ready(Ok(AddrStream::new(socket, remote_addr, local_addr)));
186207
}
187208
Err(e) => {
188209
// Connection errors can be ignored directly, continue by
@@ -262,6 +283,8 @@ mod addr_stream {
262283
use std::net::SocketAddr;
263284
#[cfg(unix)]
264285
use std::os::unix::io::{AsRawFd, RawFd};
286+
#[cfg(target_os = "wasi")]
287+
use std::os::wasi::io::{AsRawFd, RawFd};
265288
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
266289
use tokio::net::TcpStream;
267290

@@ -372,7 +395,7 @@ mod addr_stream {
372395
}
373396
}
374397

375-
#[cfg(unix)]
398+
#[cfg(any(unix, target_os = "wasi"))]
376399
impl AsRawFd for AddrStream {
377400
fn as_raw_fd(&self) -> RawFd {
378401
self.inner.as_raw_fd()

0 commit comments

Comments
 (0)