From 00cbc8d0c820b8ba09c73fe538852e1ee7d5d8d0 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 21 Jan 2022 14:19:13 +0100 Subject: [PATCH 1/2] wasi: update to wasi 0.11.0 To make use of `sock_accept()`, update the wasi crate to `0.11.0`. Signed-off-by: Harald Hoyer --- Cargo.lock | 12 ++++++--- library/std/Cargo.toml | 2 +- library/std/src/os/wasi/fs.rs | 15 +++++++++++ library/std/src/sys/wasi/mod.rs | 41 ++++++++++++++++-------------- library/std/src/sys/wasi/stdio.rs | 2 +- library/std/src/sys/wasi/thread.rs | 8 +++--- library/std/src/sys/wasi/time.rs | 2 +- 7 files changed, 54 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 738f33d3fa219..ab88bbe1491f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1473,7 +1473,7 @@ checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ "cfg-if 0.1.10", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] @@ -1484,7 +1484,7 @@ checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" dependencies = [ "cfg-if 0.1.10", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] @@ -4854,7 +4854,7 @@ dependencies = [ "rustc-demangle", "std_detect", "unwind", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -5612,6 +5612,12 @@ name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 165169aedb315..c54f38615c580 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -45,7 +45,7 @@ fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } hermit-abi = { version = "0.1.19", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] -wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false } +wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false } [features] backtrace = [ diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 5c62679f552d6..37126069f942b 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -250,6 +250,21 @@ impl FileExt for fs::File { } fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { + let advice = match advice { + a if a == wasi::ADVICE_NORMAL.raw() => wasi::ADVICE_NORMAL, + a if a == wasi::ADVICE_SEQUENTIAL.raw() => wasi::ADVICE_SEQUENTIAL, + a if a == wasi::ADVICE_RANDOM.raw() => wasi::ADVICE_RANDOM, + a if a == wasi::ADVICE_WILLNEED.raw() => wasi::ADVICE_WILLNEED, + a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED, + a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE, + _ => { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"invalid parameter 'advice'", + )); + } + }; + self.as_inner().as_inner().advise(offset, len, advice) } diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 8d62335aae5eb..f878941939ce8 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -61,23 +61,26 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { if errno > u16::MAX as i32 || errno < 0 { return Uncategorized; } - match errno as u16 { - wasi::ERRNO_CONNREFUSED => ConnectionRefused, - wasi::ERRNO_CONNRESET => ConnectionReset, - wasi::ERRNO_PERM | wasi::ERRNO_ACCES => PermissionDenied, - wasi::ERRNO_PIPE => BrokenPipe, - wasi::ERRNO_NOTCONN => NotConnected, - wasi::ERRNO_CONNABORTED => ConnectionAborted, - wasi::ERRNO_ADDRNOTAVAIL => AddrNotAvailable, - wasi::ERRNO_ADDRINUSE => AddrInUse, - wasi::ERRNO_NOENT => NotFound, - wasi::ERRNO_INTR => Interrupted, - wasi::ERRNO_INVAL => InvalidInput, - wasi::ERRNO_TIMEDOUT => TimedOut, - wasi::ERRNO_EXIST => AlreadyExists, - wasi::ERRNO_AGAIN => WouldBlock, - wasi::ERRNO_NOSYS => Unsupported, - wasi::ERRNO_NOMEM => OutOfMemory, + + match errno { + e if e == wasi::ERRNO_CONNREFUSED.raw().into() => ConnectionRefused, + e if e == wasi::ERRNO_CONNRESET.raw().into() => ConnectionReset, + e if e == wasi::ERRNO_PERM.raw().into() || e == wasi::ERRNO_ACCES.raw().into() => { + PermissionDenied + } + e if e == wasi::ERRNO_PIPE.raw().into() => BrokenPipe, + e if e == wasi::ERRNO_NOTCONN.raw().into() => NotConnected, + e if e == wasi::ERRNO_CONNABORTED.raw().into() => ConnectionAborted, + e if e == wasi::ERRNO_ADDRNOTAVAIL.raw().into() => AddrNotAvailable, + e if e == wasi::ERRNO_ADDRINUSE.raw().into() => AddrInUse, + e if e == wasi::ERRNO_NOENT.raw().into() => NotFound, + e if e == wasi::ERRNO_INTR.raw().into() => Interrupted, + e if e == wasi::ERRNO_INVAL.raw().into() => InvalidInput, + e if e == wasi::ERRNO_TIMEDOUT.raw().into() => TimedOut, + e if e == wasi::ERRNO_EXIST.raw().into() => AlreadyExists, + e if e == wasi::ERRNO_AGAIN.raw().into() => WouldBlock, + e if e == wasi::ERRNO_NOSYS.raw().into() => Unsupported, + e if e == wasi::ERRNO_NOMEM.raw().into() => OutOfMemory, _ => Uncategorized, } } @@ -96,6 +99,6 @@ pub fn hashmap_random_keys() -> (u64, u64) { return ret; } -fn err2io(err: wasi::Error) -> std_io::Error { - std_io::Error::from_raw_os_error(err.raw_error().into()) +fn err2io(err: wasi::Errno) -> std_io::Error { + std_io::Error::from_raw_os_error(err.raw().into()) } diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 2c8f394cd47b0..4cc0e4ed5a45a 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -104,7 +104,7 @@ impl io::Write for Stderr { pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(wasi::ERRNO_BADF.into()) + err.raw_os_error() == Some(wasi::ERRNO_BADF.raw().into()) } pub fn panic_output() -> Option { diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index 2e4e474c4492c..e7a6ab4be826f 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -41,8 +41,7 @@ impl Thread { let in_ = wasi::Subscription { userdata: USERDATA, - r#type: wasi::EVENTTYPE_CLOCK, - u: wasi::SubscriptionU { clock }, + u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } }, }; unsafe { let mut event: wasi::Event = mem::zeroed(); @@ -51,7 +50,10 @@ impl Thread { ( Ok(1), wasi::Event { - userdata: USERDATA, error: 0, r#type: wasi::EVENTTYPE_CLOCK, .. + userdata: USERDATA, + error: wasi::ERRNO_SUCCESS, + type_: wasi::EVENTTYPE_CLOCK, + .. }, ) => {} _ => panic!("thread::sleep(): unexpected result of poll_oneoff"), diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs index 2e720d11603a7..db0ddecf0c629 100644 --- a/library/std/src/sys/wasi/time.rs +++ b/library/std/src/sys/wasi/time.rs @@ -10,7 +10,7 @@ pub struct SystemTime(Duration); pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); -fn current_time(clock: u32) -> Duration { +fn current_time(clock: wasi::Clockid) -> Duration { let ts = unsafe { wasi::clock_time_get( clock, 1, // precision... seems ignored though? From d2a13693c2858b6b0fe1feb2dfff604bc2b0aa30 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 21 Jan 2022 14:19:48 +0100 Subject: [PATCH 2/2] wasi: enable TcpListener and TcpStream With the addition of `sock_accept()` to snapshot1, simple networking via a passed `TcpListener` is possible. This patch implements the basics to make a simple server work. Signed-off-by: Harald Hoyer --- library/std/src/os/wasi/net/mod.rs | 20 +++++++++ library/std/src/sys/wasi/fd.rs | 4 ++ library/std/src/sys/wasi/net.rs | 66 ++++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs index e6bcf87887f03..73c097d4a50ab 100644 --- a/library/std/src/os/wasi/net/mod.rs +++ b/library/std/src/os/wasi/net/mod.rs @@ -1,3 +1,23 @@ //! WASI-specific networking functionality #![unstable(feature = "wasi_ext", issue = "71213")] + +use crate::io; +use crate::net; +use crate::sys_common::AsInner; + +/// WASI-specific extensions to [`std::net::TcpListener`]. +/// +/// [`std::net::TcpListener`]: crate::net::TcpListener +pub trait TcpListenerExt { + /// Accept a socket. + /// + /// This corresponds to the `sock_accept` syscall. + fn sock_accept(&self, flags: u16) -> io::Result; +} + +impl TcpListenerExt for net::TcpListener { + fn sock_accept(&self, flags: u16) -> io::Result { + self.as_inner().as_inner().as_inner().sock_accept(flags) + } +} diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index e4f4456611cd0..0b9c8e61db84c 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -228,6 +228,10 @@ impl WasiFd { unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } } + pub fn sock_accept(&self, flags: wasi::Fdflags) -> io::Result { + unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) } + } + pub fn sock_recv( &self, ri_data: &mut [IoSliceMut<'_>], diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index a4dbb225376ee..c66e0e4d328ad 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -1,5 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] +use super::err2io; use super::fd::WasiFd; use crate::convert::TryFrom; use crate::fmt; @@ -87,24 +88,24 @@ impl TcpStream { unsupported() } - pub fn read(&self, _: &mut [u8]) -> io::Result { - unsupported() + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.read_vectored(&mut [IoSliceMut::new(buf)]) } - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - unsupported() + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.socket().as_inner().read(bufs) } pub fn is_read_vectored(&self) -> bool { true } - pub fn write(&self, _: &[u8]) -> io::Result { - unsupported() + pub fn write(&self, buf: &[u8]) -> io::Result { + self.write_vectored(&[IoSlice::new(buf)]) } - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - unsupported() + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.socket().as_inner().write(bufs) } pub fn is_write_vectored(&self) -> bool { @@ -155,8 +156,23 @@ impl TcpStream { unsupported() } - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unsupported() + pub fn set_nonblocking(&self, state: bool) -> io::Result<()> { + let fdstat = unsafe { + wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)? + }; + + let mut flags = fdstat.fs_flags; + + if state { + flags |= wasi::FDFLAGS_NONBLOCK; + } else { + flags &= !wasi::FDFLAGS_NONBLOCK; + } + + unsafe { + wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags) + .map_err(err2io) + } } pub fn socket(&self) -> &Socket { @@ -194,7 +210,16 @@ impl TcpListener { } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - unsupported() + let fd = unsafe { + wasi::sock_accept(self.as_inner().as_inner().as_raw_fd() as _, 0).map_err(err2io)? + }; + + Ok(( + TcpStream::from_inner(unsafe { Socket::from_raw_fd(fd as _) }), + // WASI has no concept of SocketAddr yet + // return an unspecified IPv4Addr + SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0), + )) } pub fn duplicate(&self) -> io::Result { @@ -221,8 +246,23 @@ impl TcpListener { unsupported() } - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - unsupported() + pub fn set_nonblocking(&self, state: bool) -> io::Result<()> { + let fdstat = unsafe { + wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)? + }; + + let mut flags = fdstat.fs_flags; + + if state { + flags |= wasi::FDFLAGS_NONBLOCK; + } else { + flags &= !wasi::FDFLAGS_NONBLOCK; + } + + unsafe { + wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags) + .map_err(err2io) + } } pub fn socket(&self) -> &Socket {