From 7c532813e73eed26e4d7d6224e0477f818873ca1 Mon Sep 17 00:00:00 2001 From: Johnathan Sharratt Date: Thu, 28 Oct 2021 12:09:00 +0100 Subject: [PATCH 1/9] Multiple changes required to implement the wasmer terminal on the browser - Split functionality out of WasiEnv so that it can support multi-threading - Added methods to the VFS File Trait that supporting polling - Implemented basic time functionality for WASI - Incorported a yield callback for when WASI processes idle - Improved the error handling on WASI IO calls - Reduce the verbose logging on some critical WASI calls (write/read) - Implemented the missing poll functionality for WASI processes - Moved the syspoll functionality behind a feature flag to default to WASI method - Refactored the thread sleeping functionality for WASI processes - Fixed the files system benchmark which was not compiling - Modified the file system trait so that it is SYNC and thus can handle multiple threads - Removed the large mutex around filesystem state and implemented granular locks instead (this is needed to fix a deadlock scenario on the terminal) - Split the inodes object apart from the state to fix the deadlock scenario. - Few minor fixes to some warnings when not using certain features - Sleeping will now call a callback that can be used by the runtime operator when a WASI thread goes to sleep (for instance to do other work) - Fixed a bug where paths that exist on the real file system are leaking into VFS - Timing functions now properly return a time precision on WASI - Some improved macros for error handling within syscalls (wasi_try_ok!) - Refactored the remove_directory WASI function which was not working properly - Refactored the unlink WASI function which was not working properly - Refactored the poll WASI function which was not working properly - Updates some of the tests to make them compile again - Rewrote the OutputCapturer so that it does leak into the internals --- Cargo.lock | 52 +- examples/wasi.rs | 5 +- examples/wasi_pipes.rs | 5 +- lib/api/src/js/externals/memory.rs | 22 +- lib/api/src/js/native.rs | 1 + lib/c-api/src/wasm_c_api/unstable/wasi.rs | 5 +- lib/c-api/src/wasm_c_api/wasi/mod.rs | 8 +- lib/cache/benches/bench_filesystem_cache.rs | 5 +- lib/cli-compiler/src/store.rs | 4 +- lib/cli/src/commands/run/wasi.rs | 3 +- lib/vfs/src/host_fs.rs | 4 +- lib/vfs/src/lib.rs | 31 +- lib/vfs/src/mem_fs/file_opener.rs | 2 +- lib/wasi-experimental-io-devices/src/lib.rs | 9 +- lib/wasi/Cargo.toml | 7 +- lib/wasi/README.md | 3 +- lib/wasi/src/lib.rs | 372 ++-- lib/wasi/src/macros.rs | 48 +- lib/wasi/src/state/builder.rs | 99 +- lib/wasi/src/state/mod.rs | 743 +++++--- lib/wasi/src/state/types.rs | 81 +- lib/wasi/src/syscalls/legacy/snapshot0.rs | 46 +- lib/wasi/src/syscalls/mod.rs | 1696 +++++++++++-------- lib/wasi/src/syscalls/unix/mod.rs | 19 +- lib/wasi/src/syscalls/wasm32.rs | 25 +- lib/wasi/src/syscalls/windows.rs | 23 +- lib/wasi/src/utils.rs | 27 + lib/wasi/tests/js.rs | 10 +- tests/compilers/config.rs | 3 +- tests/lib/wast/src/wasi_wast.rs | 91 +- 30 files changed, 2152 insertions(+), 1297 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a11542bcb9..4681497240c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,6 +307,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "js-sys", + "libc", + "num-integer", + "num-traits", + "time 0.1.43", + "wasm-bindgen", + "winapi", +] + [[package]] name = "clang-sys" version = "1.3.3" @@ -665,6 +680,17 @@ dependencies = [ "syn", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derive_arbitrary" version = "1.1.0" @@ -1387,6 +1413,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -2358,6 +2394,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "time" version = "0.2.27" @@ -2978,7 +3024,7 @@ dependencies = [ "lazy_static", "libc", "log", - "time", + "time 0.2.27", "wasmer", ] @@ -3176,6 +3222,8 @@ version = "2.3.0" dependencies = [ "bincode", "cfg-if 1.0.0", + "chrono", + "derivative", "generational-arena", "getrandom", "libc", @@ -3211,7 +3259,7 @@ version = "2.3.0" dependencies = [ "byteorder", "serde", - "time", + "time 0.2.27", "wasmer-derive", "wasmer-types", ] diff --git a/examples/wasi.rs b/examples/wasi.rs index 3d24c5af60b..d886a2acc87 100644 --- a/examples/wasi.rs +++ b/examples/wasi.rs @@ -40,7 +40,7 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` - let mut wasi_env = WasiState::new("hello") + let wasi_env = WasiState::new("hello") // .args(&["world"]) // .env("KEY", "Value") .finalize()?; @@ -48,7 +48,8 @@ fn main() -> Result<(), Box> { println!("Instantiating module with WASI imports..."); // Then, we get the import object related to our WASI // and attach it to the Wasm instance. - let import_object = wasi_env.import_object(&module)?; + let mut wasi_thread = wasi_env.new_thread(); + let import_object = wasi_thread.import_object(&module)?; let instance = Instance::new(&module, &import_object)?; println!("Call WASI `_start` function..."); diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index b1d44e119b4..1367a3af255 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -38,7 +38,7 @@ fn main() -> Result<(), Box> { // First, we create the `WasiEnv` with the stdio pipes let input = Pipe::new(); let output = Pipe::new(); - let mut wasi_env = WasiState::new("hello") + let wasi_env = WasiState::new("hello") .stdin(Box::new(input)) .stdout(Box::new(output)) .finalize()?; @@ -46,7 +46,8 @@ fn main() -> Result<(), Box> { println!("Instantiating module with WASI imports..."); // Then, we get the import object related to our WASI // and attach it to the Wasm instance. - let import_object = wasi_env.import_object(&module)?; + let mut wasi_thread = wasi_env.new_thread(); + let import_object = wasi_thread.import_object(&module)?; let instance = Instance::new(&module, &import_object)?; let msg = "racecar go zoom"; diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index d7c9460d3a1..eb9eb7317d1 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -237,10 +237,8 @@ impl Memory { Ok(Pages(new_pages)) } - /// Used by tests - #[doc(hidden)] - pub fn uint8view(&self) -> js_sys::Uint8Array { - self.view.clone() + pub(crate) fn uint8view(&self) -> js_sys::Uint8Array { + js_sys::Uint8Array::new(&self.vm_memory.memory.buffer()) } pub(crate) fn from_vm_export(store: &Store, vm_memory: VMMemory) -> Self { @@ -276,16 +274,17 @@ impl Memory { /// This method is guaranteed to be safe (from the host side) in the face of /// concurrent writes. pub fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> { + let view = self.uint8view(); let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?; let len: u32 = buf .len() .try_into() .map_err(|_| MemoryAccessError::Overflow)?; let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?; - if end > self.view.length() { + if end > view.length() { Err(MemoryAccessError::HeapOutOfBounds)?; } - self.view.subarray(offset, end).copy_to(buf); + view.subarray(offset, end).copy_to(buf); Ok(()) } @@ -304,13 +303,14 @@ impl Memory { offset: u64, buf: &'a mut [MaybeUninit], ) -> Result<&'a mut [u8], MemoryAccessError> { + let view = self.uint8view(); let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?; let len: u32 = buf .len() .try_into() .map_err(|_| MemoryAccessError::Overflow)?; let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?; - if end > self.view.length() { + if end > view.length() { Err(MemoryAccessError::HeapOutOfBounds)?; } @@ -321,7 +321,7 @@ impl Memory { } let buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len()) }; - self.view.subarray(offset, end).copy_to(buf); + view.subarray(offset, end).copy_to(buf); Ok(buf) } @@ -333,16 +333,18 @@ impl Memory { /// This method is guaranteed to be safe (from the host side) in the face of /// concurrent reads/writes. pub fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> { + let view = self.uint8view(); let offset: u32 = offset.try_into().map_err(|_| MemoryAccessError::Overflow)?; let len: u32 = data .len() .try_into() .map_err(|_| MemoryAccessError::Overflow)?; + let view = self.uint8view(); let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?; - if end > self.view.length() { + if end > view.length() { Err(MemoryAccessError::HeapOutOfBounds)?; } - self.view.subarray(offset, end).copy_from(data); + view.subarray(offset, end).copy_from(data); Ok(()) } } diff --git a/lib/api/src/js/native.rs b/lib/api/src/js/native.rs index 91342b5d229..4d56cb96c30 100644 --- a/lib/api/src/js/native.rs +++ b/lib/api/src/js/native.rs @@ -28,6 +28,7 @@ pub struct TypedFunction { } unsafe impl Send for TypedFunction {} +unsafe impl Sync for TypedFunction {} impl TypedFunction where diff --git a/lib/c-api/src/wasm_c_api/unstable/wasi.rs b/lib/c-api/src/wasm_c_api/unstable/wasi.rs index f2d1b944713..6970f722a63 100644 --- a/lib/c-api/src/wasm_c_api/unstable/wasi.rs +++ b/lib/c-api/src/wasm_c_api/unstable/wasi.rs @@ -6,7 +6,7 @@ use super::super::{ wasi::wasi_env_t, }; use wasmer_api::{Exportable, Extern}; -use wasmer_wasi::{generate_import_object_from_env, get_wasi_version}; +use wasmer_wasi::{generate_import_object_from_thread, get_wasi_version}; /// Unstable non-standard type wrapping `wasm_extern_t` with the /// addition of two `wasm_name_t` respectively for the module name and @@ -170,7 +170,8 @@ fn wasi_get_unordered_imports_inner( let version = c_try!(get_wasi_version(&module.inner, false) .ok_or("could not detect a WASI version on the given module")); - let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); + let thread = wasi_env.inner.new_thread(); + let import_object = generate_import_object_from_thread(store, thread, version); imports.set_buffer( import_object diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 63cda7d3d9d..b1146b82a28 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -19,7 +19,7 @@ use std::os::raw::c_char; use std::slice; use wasmer_api::{Exportable, Extern}; use wasmer_wasi::{ - generate_import_object_from_env, get_wasi_version, WasiEnv, WasiFile, WasiState, + generate_import_object_from_thread, get_wasi_version, WasiEnv, WasiFile, WasiState, WasiStateBuilder, WasiVersion, }; @@ -229,7 +229,8 @@ pub unsafe extern "C" fn wasi_env_read_stderr( ) -> isize { let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len as usize); let mut state = env.inner.state(); - let stderr = if let Ok(stderr) = state.fs.stderr_mut() { + let inodes = state.inodes.write().unwrap(); + let stderr = if let Ok(stderr) = inodes.stderr_mut(&state.fs.fd_map) { if let Some(stderr) = stderr.as_mut() { stderr } else { @@ -345,7 +346,8 @@ fn wasi_get_imports_inner( let version = c_try!(get_wasi_version(&module.inner, false) .ok_or("could not detect a WASI version on the given module")); - let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); + let mut thread = wasi_env.inner.new_thread(); + let import_object = generate_import_object_from_thread(store, thread, version); imports.set_buffer(c_try!(module .inner diff --git a/lib/cache/benches/bench_filesystem_cache.rs b/lib/cache/benches/bench_filesystem_cache.rs index f9adc74b3d6..efd942c96a4 100644 --- a/lib/cache/benches/bench_filesystem_cache.rs +++ b/lib/cache/benches/bench_filesystem_cache.rs @@ -1,3 +1,4 @@ +#![allow(unused_imports)] use criterion::{black_box, criterion_group, criterion_main, Criterion}; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -54,7 +55,7 @@ pub fn store_cache_native(c: &mut Criterion) { let tmp_dir = TempDir::new().unwrap(); let mut fs_cache = FileSystemCache::new(tmp_dir.path()).unwrap(); let compiler = Singlepass::default(); - let store = Store::new(&Native::new(compiler).engine()); + let store = Store::new(&Universal::new(compiler).engine()); let module = Module::new( &store, std::fs::read("../../lib/c-api/examples/assets/qjs.wasm").unwrap(), @@ -73,7 +74,7 @@ pub fn load_cache_native(c: &mut Criterion) { let tmp_dir = TempDir::new().unwrap(); let mut fs_cache = FileSystemCache::new(tmp_dir.path()).unwrap(); let compiler = Singlepass::default(); - let store = Store::new(&Native::new(compiler).engine()); + let store = Store::new(&Universal::new(compiler).engine()); let module = Module::new( &store, std::fs::read("../../lib/c-api/examples/assets/qjs.wasm").unwrap(), diff --git a/lib/cli-compiler/src/store.rs b/lib/cli-compiler/src/store.rs index 16f8691ca7c..096e871bcba 100644 --- a/lib/cli-compiler/src/store.rs +++ b/lib/cli-compiler/src/store.rs @@ -107,13 +107,15 @@ pub struct CompilerOptions { llvm: bool, /// Enable compiler internal verification. + #[allow(unused)] #[structopt(long)] #[allow(dead_code)] enable_verifier: bool, /// LLVM debug directory, where IR and object files will be written to. + #[allow(unused)] #[cfg(feature = "llvm")] - #[structopt(long, parse(from_os_str))] + #[cfg_attr(feature = "llvm", structopt(long, parse(from_os_str)))] llvm_debug_dir: Option, #[structopt(flatten)] diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index b7adf3a091f..0c697e5e3fb 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -41,7 +41,7 @@ pub struct Wasi { /// Enable experimental IO devices #[cfg(feature = "experimental-io-devices")] - #[structopt(long = "enable-experimental-io-devices")] + #[cfg_attr(feature = "experimental-io-devices", structopt(long = "enable-experimental-io-devices"))] enable_experimental_io_devices: bool, /// Allow WASI modules to import multiple versions of WASI without a warning. @@ -94,6 +94,7 @@ impl Wasi { } let mut wasi_env = wasi_state_builder.finalize()?; + let mut wasi_thread = wasi_env.new_thread(); let import_object = wasi_env.import_object_for_all_wasi_versions(module)?; let instance = Instance::new(module, &import_object)?; Ok(instance) diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index 961f6685be0..e058839ed8e 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -177,7 +177,7 @@ impl TryInto for fs::Metadata { pub struct FileOpener; impl crate::FileOpener for FileOpener { - fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result> { + fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result> { // TODO: handle create implying write, etc. let read = conf.read(); let write = conf.write(); @@ -193,7 +193,7 @@ impl crate::FileOpener for FileOpener { .map_err(Into::into) .map(|file| { Box::new(File::new(file, path.to_owned(), read, write, append)) - as Box + as Box }) } } diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index f1274a0f655..ccb49bf944b 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -51,7 +51,7 @@ impl dyn FileSystem + 'static { } pub trait FileOpener { - fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result>; + fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result>; } #[derive(Debug, Clone)] @@ -111,6 +111,10 @@ impl OpenOptions { }, } } + pub fn options(&mut self, options: OpenOptionsConfig) -> &mut Self { + self.conf = options; + self + } pub fn read(&mut self, read: bool) -> &mut Self { self.conf.read = read; @@ -142,7 +146,7 @@ impl OpenOptions { self } - pub fn open>(&mut self, path: P) -> Result> { + pub fn open>(&mut self, path: P) -> Result> { self.opener.open(path.as_ref(), &self.conf) } } @@ -177,7 +181,28 @@ pub trait VirtualFile: fmt::Debug + Send + Write + Read + Seek + 'static + Upcas } /// Returns the number of bytes available. This function must not block - fn bytes_available(&self) -> Result; + fn bytes_available(&self) -> Result { + return Ok(self.bytes_available_read()?.unwrap_or(0usize) + + self.bytes_available_write()?.unwrap_or(0usize)); + } + + /// Returns the number of bytes available. This function must not block + /// Defaults to `None` which means the number of bytes is unknown + fn bytes_available_read(&self) -> Result> { + Ok(None) + } + + /// Returns the number of bytes available. This function must not block + /// Defaults to `None` which means the number of bytes is unknown + fn bytes_available_write(&self) -> Result> { + Ok(None) + } + + /// Indicates if the file is opened or closed. This function must not block + /// Defaults to a status of being constantly open + fn is_open(&self) -> bool { + true + } /// Used for polling. Default returns `None` because this method cannot be implemented for most types /// Returns the underlying host fd diff --git a/lib/vfs/src/mem_fs/file_opener.rs b/lib/vfs/src/mem_fs/file_opener.rs index 689feb5aafd..6e80dbd1be6 100644 --- a/lib/vfs/src/mem_fs/file_opener.rs +++ b/lib/vfs/src/mem_fs/file_opener.rs @@ -10,7 +10,7 @@ pub struct FileOpener { } impl crate::FileOpener for FileOpener { - fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result> { + fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result> { let read = conf.read(); let mut write = conf.write(); let append = conf.append(); diff --git a/lib/wasi-experimental-io-devices/src/lib.rs b/lib/wasi-experimental-io-devices/src/lib.rs index 66b910bf7db..04008e359ce 100644 --- a/lib/wasi-experimental-io-devices/src/lib.rs +++ b/lib/wasi-experimental-io-devices/src/lib.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeSet, VecDeque}; use std::convert::TryInto; use std::io::{Read, Seek, SeekFrom, Write}; use tracing::debug; -use wasmer_wasi::types::*; +use wasmer_wasi::{types::*, WasiInodes}; use wasmer_wasi::{Fd, VirtualFile, WasiFs, WasiFsError, ALL_RIGHTS, VIRTUAL_ROOT_FD}; use minifb::{Key, KeyRepeat, MouseButton, Scale, Window, WindowOptions}; @@ -426,7 +426,7 @@ impl VirtualFile for FrameBuffer { } } -pub fn initialize(fs: &mut WasiFs) -> Result<(), String> { +pub fn initialize(inodes: &mut WasiInodes, fs: &mut WasiFs) -> Result<(), String> { let frame_buffer_file = Box::new(FrameBuffer { fb_type: FrameBufferFileType::Buffer, cursor: 0, @@ -446,6 +446,7 @@ pub fn initialize(fs: &mut WasiFs) -> Result<(), String> { let base_dir_fd = unsafe { fs.open_dir_all( + inodes, VIRTUAL_ROOT_FD, "_wasmer/dev/fb0".to_string(), ALL_RIGHTS, @@ -457,6 +458,7 @@ pub fn initialize(fs: &mut WasiFs) -> Result<(), String> { let _fd = fs .open_file_at( + inodes, base_dir_fd, input_file, Fd::READ, @@ -471,6 +473,7 @@ pub fn initialize(fs: &mut WasiFs) -> Result<(), String> { let _fd = fs .open_file_at( + inodes, base_dir_fd, frame_buffer_file, Fd::READ | Fd::WRITE, @@ -485,6 +488,7 @@ pub fn initialize(fs: &mut WasiFs) -> Result<(), String> { let _fd = fs .open_file_at( + inodes, base_dir_fd, resolution_file, Fd::READ | Fd::WRITE, @@ -499,6 +503,7 @@ pub fn initialize(fs: &mut WasiFs) -> Result<(), String> { let _fd = fs .open_file_at( + inodes, base_dir_fd, draw_file, Fd::READ | Fd::WRITE, diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index d6806c48eb2..7d85a721d17 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -25,6 +25,8 @@ wasmer-vfs = { path = "../vfs", version = "=2.3.0", default-features = false } typetag = { version = "0.1", optional = true } serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } bincode = { version = "1.3", optional = true } +chrono = { version = "^0.4", features = [ "wasmbind" ], optional = true } +derivative = { version = "^2" } [target.'cfg(unix)'.dependencies] libc = { version = "^0.2", default-features = false } @@ -43,9 +45,10 @@ tracing-wasm = "0.2" default = ["sys-default"] sys = ["wasmer/sys"] -sys-default = ["wasmer/sys-default", "sys", "logging", "host-fs"] +sys-default = ["wasmer/sys-default", "sys", "logging", "host-fs", "sys-poll"] +sys-poll = [] -js = ["wasmer/js", "mem-fs", "wasmer-vfs/no-time", "getrandom/js"] +js = ["wasmer/js", "mem-fs", "wasmer-vfs/no-time", "getrandom/js", "chrono"] js-default = ["js", "wasmer/js-default"] test-js = ["js", "wasmer/js-default", "wasmer/wat"] diff --git a/lib/wasi/README.md b/lib/wasi/README.md index 4d4d13529fc..f2b97bb105b 100644 --- a/lib/wasi/README.md +++ b/lib/wasi/README.md @@ -66,7 +66,8 @@ let wasi_env = WasiState::new("command-name") .finalize()?; // Generate an `ImportObject`. -let import_object = wasi_env.import_object(&module)?; +let mut wasi_thread = wasi_env.new_thread(); +let import_object = wasi_thread.import_object(&module)?; // Let's instantiate the module with the imports. let instance = Instance::new(&module, &import_object)?; diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 6ffda3c848b..bb5506add10 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -42,7 +42,7 @@ mod utils; use crate::syscalls::*; pub use crate::state::{ - Fd, Pipe, Stderr, Stdin, Stdout, WasiFs, WasiState, WasiStateBuilder, WasiStateCreationError, + Fd, Pipe, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder, WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, }; pub use crate::syscalls::types; @@ -52,13 +52,17 @@ pub use wasmer_vfs::FsError as WasiFsError; #[deprecated(since = "2.1.0", note = "Please use `wasmer_vfs::VirtualFile`")] pub use wasmer_vfs::VirtualFile as WasiFile; pub use wasmer_vfs::{FsError, VirtualFile}; +use wasmer_wasi_types::__WASI_CLOCK_MONOTONIC; +use derivative::*; +use std::ops::Deref; use thiserror::Error; use wasmer::{ imports, Function, Imports, LazyInit, Memory, MemoryAccessError, Module, Store, WasmerEnv, }; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::time::Duration; +use std::sync::{atomic::AtomicU32, atomic::Ordering, Arc, RwLockReadGuard, RwLockWriteGuard}; /// This is returned in `RuntimeError`. /// Use `downcast` or `downcast_ref` to retrieve the `ExitCode`. @@ -70,32 +74,112 @@ pub enum WasiError { UnknownWasiVersion, } -/// The environment provided to the WASI imports. +/// WASI processes can have multiple threads attached to the same environment #[derive(Debug, Clone, WasmerEnv)] -pub struct WasiEnv { - /// Shared state of the WASI system. Manages all the data that the - /// executing WASI program can see. - /// - /// Be careful when using this in host functions that call into Wasm: - /// if the lock is held and the Wasm calls into a host function that tries - /// to lock this mutex, the program will deadlock. - pub state: Arc>, +pub struct WasiThread { + /// ID of this thread + id: u32, + /// Provides access to the WASI environment + env: WasiEnv, #[wasmer(export)] memory: LazyInit, } -impl WasiEnv { - pub fn new(state: WasiState) -> Self { - Self { - state: Arc::new(Mutex::new(state)), - memory: LazyInit::new(), +/// The WASI thread dereferences into the WASI environment +impl Deref for WasiThread { + type Target = WasiEnv; + + fn deref(&self) -> &WasiEnv { + &self.env + } +} + +impl WasiThread { + /// Returns the unique ID of this thread + pub fn thread_id(&self) -> u32 { + self.id + } + + /// Yields execution + pub fn yield_callback(&self) -> Result<(), WasiError> { + if let Some(callback) = self.on_yield.as_ref() { + callback(self)?; } + Ok(()) + } + + // Yields execution + pub fn yield_now(&self) -> Result<(), WasiError> { + self.yield_callback()?; + Ok(()) + } + + // Sleeps for a period of time + pub fn sleep(&self, duration: Duration) -> Result<(), WasiError> { + let duration = duration.as_nanos(); + let start = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + self.yield_now()?; + loop { + let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let delta = match now.checked_sub(start) { + Some(a) => a, + None => { break; } + }; + if delta >= duration { + break; + } + let remaining = match duration.checked_sub(delta) { + Some(a) => Duration::from_nanos(a as u64), + None => { break; } + }; + std::thread::sleep(remaining.min(Duration::from_millis(10))); + self.yield_now()?; + } + Ok(()) + } + + /// Get a reference to the memory + pub fn memory(&self) -> &Memory { + self.memory_ref() + .expect("Memory should be set on `WasiEnv` first") + } + + // Copy the lazy reference so that when its initialized during the + // export phase that all the other references get a copy of it + pub fn memory_clone(&self) -> LazyInit { + self.memory.clone() + } + + pub(crate) fn get_memory_and_wasi_state(&self, _mem_index: u32) -> (&Memory, &WasiState) { + let memory = self.memory(); + let state = self.state.deref(); + (memory, state) + } + + pub(crate) fn get_memory_and_wasi_state_and_inodes( + &self, + _mem_index: u32, + ) -> (&Memory, &WasiState, RwLockReadGuard) { + let memory = self.memory(); + let state = self.state.deref(); + let inodes = state.inodes.read().unwrap(); + (memory, state, inodes) + } + + pub(crate) fn get_memory_and_wasi_state_and_inodes_mut( + &self, + _mem_index: u32, + ) -> (&Memory, &WasiState, RwLockWriteGuard) { + let memory = self.memory(); + let state = self.state.deref(); + let inodes = state.inodes.write().unwrap(); + (memory, state, inodes) } /// Get an `Imports` for a specific version of WASI detected in the module. pub fn import_object(&mut self, module: &Module) -> Result { let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?; - Ok(generate_import_object_from_env( + Ok(generate_import_object_from_thread( module.store(), self.clone(), wasi_version, @@ -114,157 +198,197 @@ impl WasiEnv { let mut resolver = Imports::new(); for version in wasi_versions.iter() { let new_import_object = - generate_import_object_from_env(module.store(), self.clone(), *version); + generate_import_object_from_thread(module.store(), self.clone(), *version); for ((n, m), e) in new_import_object.into_iter() { resolver.define(&n, &m, e); } } Ok(resolver) } +} + +/// The environment provided to the WASI imports. +#[derive(Derivative, Clone)] +#[derivative(Debug)] +pub struct WasiEnv { + /// Represents a reference to the memory + memory: LazyInit, + /// Shared state of the WASI system. Manages all the data that the + /// executing WASI program can see. + /// + /// Holding a read lock across WASM calls now is allowed + pub state: Arc, + /// Optional callback thats invoked whenever a syscall is made + /// which is used to make callbacks to the process without breaking + /// the single threaded WASM modules + #[derivative(Debug = "ignore")] + pub(crate) on_yield: Option Result<(), WasiError> + Send + Sync + 'static>>, + /// The thread ID seed is used to generate unique thread identifiers + /// for each WasiThread. These are needed for multithreading code that needs + /// this information in the syscalls + pub(crate) thread_id_seed: Arc, +} + +impl WasiEnv { + pub fn new(state: WasiState) -> Self { + Self { + state: Arc::new(state), + memory: LazyInit::new(), + on_yield: None, + thread_id_seed: Arc::new(AtomicU32::new(1u32)), + } + } + + /// Creates a new thread only this wasi environment + pub fn new_thread(&self) -> WasiThread { + WasiThread { + id: self.thread_id_seed.fetch_add(1, Ordering::Relaxed), + env: self.clone(), + memory: self.memory_clone(), + } + } /// Get the WASI state /// /// Be careful when using this in host functions that call into Wasm: /// if the lock is held and the Wasm calls into a host function that tries /// to lock this mutex, the program will deadlock. - pub fn state(&self) -> MutexGuard { - self.state.lock().unwrap() + pub fn state(&self) -> &WasiState { + self.state.deref() } /// Get a reference to the memory pub fn memory(&self) -> &Memory { - self.memory_ref() + self.memory + .get_ref() .expect("Memory should be set on `WasiEnv` first") } - pub(crate) fn get_memory_and_wasi_state( - &self, - _mem_index: u32, - ) -> (&Memory, MutexGuard) { - let memory = self.memory(); - let state = self.state.lock().unwrap(); - (memory, state) + /// Copy the lazy reference so that when it's initialized during the + /// export phase, all the other references get a copy of it + pub fn memory_clone(&self) -> LazyInit { + self.memory.clone() } } /// Create an [`Imports`] with an existing [`WasiEnv`]. `WasiEnv` /// needs a [`WasiState`], that can be constructed from a /// [`WasiStateBuilder`](state::WasiStateBuilder). -pub fn generate_import_object_from_env( +pub fn generate_import_object_from_thread( store: &Store, - wasi_env: WasiEnv, + thread: WasiThread, version: WasiVersion, ) -> Imports { match version { - WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, wasi_env), + WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, thread), WasiVersion::Snapshot1 | WasiVersion::Latest => { - generate_import_object_snapshot1(store, wasi_env) + generate_import_object_snapshot1(store, thread) } } } /// Combines a state generating function with the import list for legacy WASI -fn generate_import_object_snapshot0(store: &Store, env: WasiEnv) -> Imports { +fn generate_import_object_snapshot0(store: &Store, thread: WasiThread) -> Imports { imports! { "wasi_unstable" => { - "args_get" => Function::new_native_with_env(store, env.clone(), args_get), - "args_sizes_get" => Function::new_native_with_env(store, env.clone(), args_sizes_get), - "clock_res_get" => Function::new_native_with_env(store, env.clone(), clock_res_get), - "clock_time_get" => Function::new_native_with_env(store, env.clone(), clock_time_get), - "environ_get" => Function::new_native_with_env(store, env.clone(), environ_get), - "environ_sizes_get" => Function::new_native_with_env(store, env.clone(), environ_sizes_get), - "fd_advise" => Function::new_native_with_env(store, env.clone(), fd_advise), - "fd_allocate" => Function::new_native_with_env(store, env.clone(), fd_allocate), - "fd_close" => Function::new_native_with_env(store, env.clone(), fd_close), - "fd_datasync" => Function::new_native_with_env(store, env.clone(), fd_datasync), - "fd_fdstat_get" => Function::new_native_with_env(store, env.clone(), fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_native_with_env(store, env.clone(), legacy::snapshot0::fd_filestat_get), - "fd_filestat_set_size" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_times), - "fd_pread" => Function::new_native_with_env(store, env.clone(), fd_pread), - "fd_prestat_get" => Function::new_native_with_env(store, env.clone(), fd_prestat_get), - "fd_prestat_dir_name" => Function::new_native_with_env(store, env.clone(), fd_prestat_dir_name), - "fd_pwrite" => Function::new_native_with_env(store, env.clone(), fd_pwrite), - "fd_read" => Function::new_native_with_env(store, env.clone(), fd_read), - "fd_readdir" => Function::new_native_with_env(store, env.clone(), fd_readdir), - "fd_renumber" => Function::new_native_with_env(store, env.clone(), fd_renumber), - "fd_seek" => Function::new_native_with_env(store, env.clone(), legacy::snapshot0::fd_seek), - "fd_sync" => Function::new_native_with_env(store, env.clone(), fd_sync), - "fd_tell" => Function::new_native_with_env(store, env.clone(), fd_tell), - "fd_write" => Function::new_native_with_env(store, env.clone(), fd_write), - "path_create_directory" => Function::new_native_with_env(store, env.clone(), path_create_directory), - "path_filestat_get" => Function::new_native_with_env(store, env.clone(), legacy::snapshot0::path_filestat_get), - "path_filestat_set_times" => Function::new_native_with_env(store, env.clone(), path_filestat_set_times), - "path_link" => Function::new_native_with_env(store, env.clone(), path_link), - "path_open" => Function::new_native_with_env(store, env.clone(), path_open), - "path_readlink" => Function::new_native_with_env(store, env.clone(), path_readlink), - "path_remove_directory" => Function::new_native_with_env(store, env.clone(), path_remove_directory), - "path_rename" => Function::new_native_with_env(store, env.clone(), path_rename), - "path_symlink" => Function::new_native_with_env(store, env.clone(), path_symlink), - "path_unlink_file" => Function::new_native_with_env(store, env.clone(), path_unlink_file), - "poll_oneoff" => Function::new_native_with_env(store, env.clone(), legacy::snapshot0::poll_oneoff), - "proc_exit" => Function::new_native_with_env(store, env.clone(), proc_exit), - "proc_raise" => Function::new_native_with_env(store, env.clone(), proc_raise), - "random_get" => Function::new_native_with_env(store, env.clone(), random_get), - "sched_yield" => Function::new_native_with_env(store, env.clone(), sched_yield), - "sock_recv" => Function::new_native_with_env(store, env.clone(), sock_recv), - "sock_send" => Function::new_native_with_env(store, env.clone(), sock_send), - "sock_shutdown" => Function::new_native_with_env(store, env, sock_shutdown), + "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), + "args_sizes_get" => Function::new_native_with_env(store, thread.clone(), args_sizes_get), + "clock_res_get" => Function::new_native_with_env(store, thread.clone(), clock_res_get), + "clock_time_get" => Function::new_native_with_env(store, thread.clone(), clock_time_get), + "environ_get" => Function::new_native_with_env(store, thread.clone(), environ_get), + "environ_sizes_get" => Function::new_native_with_env(store, thread.clone(), environ_sizes_get), + "fd_advise" => Function::new_native_with_env(store, thread.clone(), fd_advise), + "fd_allocate" => Function::new_native_with_env(store, thread.clone(), fd_allocate), + "fd_close" => Function::new_native_with_env(store, thread.clone(), fd_close), + "fd_datasync" => Function::new_native_with_env(store, thread.clone(), fd_datasync), + "fd_fdstat_get" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_get), + "fd_fdstat_set_flags" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native_with_env(store, thread.clone(), legacy::snapshot0::fd_filestat_get), + "fd_filestat_set_size" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_times), + "fd_pread" => Function::new_native_with_env(store, thread.clone(), fd_pread), + "fd_prestat_get" => Function::new_native_with_env(store, thread.clone(), fd_prestat_get), + "fd_prestat_dir_name" => Function::new_native_with_env(store, thread.clone(), fd_prestat_dir_name), + "fd_pwrite" => Function::new_native_with_env(store, thread.clone(), fd_pwrite), + "fd_read" => Function::new_native_with_env(store, thread.clone(), fd_read), + "fd_readdir" => Function::new_native_with_env(store, thread.clone(), fd_readdir), + "fd_renumber" => Function::new_native_with_env(store, thread.clone(), fd_renumber), + "fd_seek" => Function::new_native_with_env(store, thread.clone(), legacy::snapshot0::fd_seek), + "fd_sync" => Function::new_native_with_env(store, thread.clone(), fd_sync), + "fd_tell" => Function::new_native_with_env(store, thread.clone(), fd_tell), + "fd_write" => Function::new_native_with_env(store, thread.clone(), fd_write), + "path_create_directory" => Function::new_native_with_env(store, thread.clone(), path_create_directory), + "path_filestat_get" => Function::new_native_with_env(store, thread.clone(), legacy::snapshot0::path_filestat_get), + "path_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), path_filestat_set_times), + "path_link" => Function::new_native_with_env(store, thread.clone(), path_link), + "path_open" => Function::new_native_with_env(store, thread.clone(), path_open), + "path_readlink" => Function::new_native_with_env(store, thread.clone(), path_readlink), + "path_remove_directory" => Function::new_native_with_env(store, thread.clone(), path_remove_directory), + "path_rename" => Function::new_native_with_env(store, thread.clone(), path_rename), + "path_symlink" => Function::new_native_with_env(store, thread.clone(), path_symlink), + "path_unlink_file" => Function::new_native_with_env(store, thread.clone(), path_unlink_file), + "poll_oneoff" => Function::new_native_with_env(store, thread.clone(), legacy::snapshot0::poll_oneoff), + "proc_exit" => Function::new_native_with_env(store, thread.clone(), proc_exit), + "proc_raise" => Function::new_native_with_env(store, thread.clone(), proc_raise), + "random_get" => Function::new_native_with_env(store, thread.clone(), random_get), + "sched_yield" => Function::new_native_with_env(store, thread.clone(), sched_yield), + "sock_recv" => Function::new_native_with_env(store, thread.clone(), sock_recv), + "sock_send" => Function::new_native_with_env(store, thread.clone(), sock_send), + "sock_shutdown" => Function::new_native_with_env(store, thread, sock_shutdown), }, } } /// Combines a state generating function with the import list for snapshot 1 -fn generate_import_object_snapshot1(store: &Store, env: WasiEnv) -> Imports { +fn generate_import_object_snapshot1(store: &Store, thread: WasiThread) -> Imports { imports! { "wasi_snapshot_preview1" => { - "args_get" => Function::new_native_with_env(store, env.clone(), args_get), - "args_sizes_get" => Function::new_native_with_env(store, env.clone(), args_sizes_get), - "clock_res_get" => Function::new_native_with_env(store, env.clone(), clock_res_get), - "clock_time_get" => Function::new_native_with_env(store, env.clone(), clock_time_get), - "environ_get" => Function::new_native_with_env(store, env.clone(), environ_get), - "environ_sizes_get" => Function::new_native_with_env(store, env.clone(), environ_sizes_get), - "fd_advise" => Function::new_native_with_env(store, env.clone(), fd_advise), - "fd_allocate" => Function::new_native_with_env(store, env.clone(), fd_allocate), - "fd_close" => Function::new_native_with_env(store, env.clone(), fd_close), - "fd_datasync" => Function::new_native_with_env(store, env.clone(), fd_datasync), - "fd_fdstat_get" => Function::new_native_with_env(store, env.clone(), fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_native_with_env(store, env.clone(), fd_filestat_get), - "fd_filestat_set_size" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_times), - "fd_pread" => Function::new_native_with_env(store, env.clone(), fd_pread), - "fd_prestat_get" => Function::new_native_with_env(store, env.clone(), fd_prestat_get), - "fd_prestat_dir_name" => Function::new_native_with_env(store, env.clone(), fd_prestat_dir_name), - "fd_pwrite" => Function::new_native_with_env(store, env.clone(), fd_pwrite), - "fd_read" => Function::new_native_with_env(store, env.clone(), fd_read), - "fd_readdir" => Function::new_native_with_env(store, env.clone(), fd_readdir), - "fd_renumber" => Function::new_native_with_env(store, env.clone(), fd_renumber), - "fd_seek" => Function::new_native_with_env(store, env.clone(), fd_seek), - "fd_sync" => Function::new_native_with_env(store, env.clone(), fd_sync), - "fd_tell" => Function::new_native_with_env(store, env.clone(), fd_tell), - "fd_write" => Function::new_native_with_env(store, env.clone(), fd_write), - "path_create_directory" => Function::new_native_with_env(store, env.clone(), path_create_directory), - "path_filestat_get" => Function::new_native_with_env(store, env.clone(), path_filestat_get), - "path_filestat_set_times" => Function::new_native_with_env(store, env.clone(), path_filestat_set_times), - "path_link" => Function::new_native_with_env(store, env.clone(), path_link), - "path_open" => Function::new_native_with_env(store, env.clone(), path_open), - "path_readlink" => Function::new_native_with_env(store, env.clone(), path_readlink), - "path_remove_directory" => Function::new_native_with_env(store, env.clone(), path_remove_directory), - "path_rename" => Function::new_native_with_env(store, env.clone(), path_rename), - "path_symlink" => Function::new_native_with_env(store, env.clone(), path_symlink), - "path_unlink_file" => Function::new_native_with_env(store, env.clone(), path_unlink_file), - "poll_oneoff" => Function::new_native_with_env(store, env.clone(), poll_oneoff), - "proc_exit" => Function::new_native_with_env(store, env.clone(), proc_exit), - "proc_raise" => Function::new_native_with_env(store, env.clone(), proc_raise), - "random_get" => Function::new_native_with_env(store, env.clone(), random_get), - "sched_yield" => Function::new_native_with_env(store, env.clone(), sched_yield), - "sock_recv" => Function::new_native_with_env(store, env.clone(), sock_recv), - "sock_send" => Function::new_native_with_env(store, env.clone(), sock_send), - "sock_shutdown" => Function::new_native_with_env(store, env, sock_shutdown), + "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), + "args_sizes_get" => Function::new_native_with_env(store, thread.clone(), args_sizes_get), + "clock_res_get" => Function::new_native_with_env(store, thread.clone(), clock_res_get), + "clock_time_get" => Function::new_native_with_env(store, thread.clone(), clock_time_get), + "environ_get" => Function::new_native_with_env(store, thread.clone(), environ_get), + "environ_sizes_get" => Function::new_native_with_env(store, thread.clone(), environ_sizes_get), + "fd_advise" => Function::new_native_with_env(store, thread.clone(), fd_advise), + "fd_allocate" => Function::new_native_with_env(store, thread.clone(), fd_allocate), + "fd_close" => Function::new_native_with_env(store, thread.clone(), fd_close), + "fd_datasync" => Function::new_native_with_env(store, thread.clone(), fd_datasync), + "fd_fdstat_get" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_get), + "fd_fdstat_set_flags" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native_with_env(store, thread.clone(), fd_filestat_get), + "fd_filestat_set_size" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_times), + "fd_pread" => Function::new_native_with_env(store, thread.clone(), fd_pread), + "fd_prestat_get" => Function::new_native_with_env(store, thread.clone(), fd_prestat_get), + "fd_prestat_dir_name" => Function::new_native_with_env(store, thread.clone(), fd_prestat_dir_name), + "fd_pwrite" => Function::new_native_with_env(store, thread.clone(), fd_pwrite), + "fd_read" => Function::new_native_with_env(store, thread.clone(), fd_read), + "fd_readdir" => Function::new_native_with_env(store, thread.clone(), fd_readdir), + "fd_renumber" => Function::new_native_with_env(store, thread.clone(), fd_renumber), + "fd_seek" => Function::new_native_with_env(store, thread.clone(), fd_seek), + "fd_sync" => Function::new_native_with_env(store, thread.clone(), fd_sync), + "fd_tell" => Function::new_native_with_env(store, thread.clone(), fd_tell), + "fd_write" => Function::new_native_with_env(store, thread.clone(), fd_write), + "path_create_directory" => Function::new_native_with_env(store, thread.clone(), path_create_directory), + "path_filestat_get" => Function::new_native_with_env(store, thread.clone(), path_filestat_get), + "path_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), path_filestat_set_times), + "path_link" => Function::new_native_with_env(store, thread.clone(), path_link), + "path_open" => Function::new_native_with_env(store, thread.clone(), path_open), + "path_readlink" => Function::new_native_with_env(store, thread.clone(), path_readlink), + "path_remove_directory" => Function::new_native_with_env(store, thread.clone(), path_remove_directory), + "path_rename" => Function::new_native_with_env(store, thread.clone(), path_rename), + "path_symlink" => Function::new_native_with_env(store, thread.clone(), path_symlink), + "path_unlink_file" => Function::new_native_with_env(store, thread.clone(), path_unlink_file), + "poll_oneoff" => Function::new_native_with_env(store, thread.clone(), poll_oneoff), + "proc_exit" => Function::new_native_with_env(store, thread.clone(), proc_exit), + "proc_raise" => Function::new_native_with_env(store, thread.clone(), proc_raise), + "random_get" => Function::new_native_with_env(store, thread.clone(), random_get), + "sched_yield" => Function::new_native_with_env(store, thread.clone(), sched_yield), + "sock_recv" => Function::new_native_with_env(store, thread.clone(), sock_recv), + "sock_send" => Function::new_native_with_env(store, thread.clone(), sock_send), + "sock_shutdown" => Function::new_native_with_env(store, thread, sock_shutdown), } } } diff --git a/lib/wasi/src/macros.rs b/lib/wasi/src/macros.rs index e2488668e08..b7ad74c2893 100644 --- a/lib/wasi/src/macros.rs +++ b/lib/wasi/src/macros.rs @@ -16,9 +16,40 @@ macro_rules! wasi_try { } } }}; - ($expr:expr, $e:expr) => {{ - let opt: Option<_> = $expr; - wasi_try!(opt.ok_or($e)) +} + +/// Like the `try!` macro or `?` syntax: returns the value if the computation +/// succeeded or returns the error value. Results are wrapped in an Ok +macro_rules! wasi_try_ok { + ($expr:expr) => {{ + let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr; + match res { + Ok(val) => { + tracing::trace!("wasi::wasi_try_ok::val: {:?}", val); + val + } + Err(err) => { + tracing::trace!("wasi::wasi_try_ok::err: {:?}", err); + return Ok(err); + } + } + }}; + + ($expr:expr, $thread:expr) => {{ + let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr; + match res { + Ok(val) => { + tracing::trace!("wasi::wasi_try_ok::val: {:?}", val); + val + } + Err(err) => { + if err == __WASI_EINTR { + $thread.yield_callback()?; + } + tracing::trace!("wasi::wasi_try_ok::err: {:?}", err); + return Ok(err); + } + } }}; } @@ -29,6 +60,17 @@ macro_rules! wasi_try_mem { }}; } +/// Like `wasi_try` but converts a `MemoryAccessError` to a __wasi_errno_t`. +macro_rules! wasi_try_mem_ok { + ($expr:expr) => {{ + wasi_try_ok!($expr.map_err($crate::mem_error_to_wasi)) + }}; + + ($expr:expr, $thread:expr) => {{ + wasi_try_ok!($expr.map_err($crate::mem_error_to_wasi), $thread) + }}; +} + /// Reads a string from Wasm memory. macro_rules! get_input_str { ($memory:expr, $data:expr, $len:expr) => {{ diff --git a/lib/wasi/src/state/builder.rs b/lib/wasi/src/state/builder.rs index 37bf5c9d37b..773daad4d98 100644 --- a/lib/wasi/src/state/builder.rs +++ b/lib/wasi/src/state/builder.rs @@ -2,8 +2,13 @@ use crate::state::{default_fs_backing, WasiFs, WasiState}; use crate::syscalls::types::{__WASI_STDERR_FILENO, __WASI_STDIN_FILENO, __WASI_STDOUT_FILENO}; -use crate::WasiEnv; +use crate::{WasiEnv, WasiInodes, WasiThread, WasiError}; +use generational_arena::Arena; +use std::collections::HashMap; +use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::sync::RwLock; use thiserror::Error; use wasmer_vfs::{FsError, VirtualFile}; @@ -40,11 +45,12 @@ pub struct WasiStateBuilder { preopens: Vec, vfs_preopens: Vec, #[allow(clippy::type_complexity)] - setup_fs_fn: Option Result<(), String> + Send>>, - stdout_override: Option>, - stderr_override: Option>, - stdin_override: Option>, + setup_fs_fn: Option Result<(), String> + Send>>, + stdout_override: Option>, + stderr_override: Option>, + stdin_override: Option>, fs_override: Option>, + on_yield: Option Result<(), WasiError> + Send + Sync + 'static>>, } impl std::fmt::Debug for WasiStateBuilder { @@ -55,6 +61,7 @@ impl std::fmt::Debug for WasiStateBuilder { .field("envs", &self.envs) .field("preopens", &self.preopens) .field("setup_fs_fn exists", &self.setup_fs_fn.is_some()) + .field("on_yield exists", &self.on_yield.is_some()) .field("stdout_override exists", &self.stdout_override.is_some()) .field("stderr_override exists", &self.stderr_override.is_some()) .field("stdin_override exists", &self.stdin_override.is_some()) @@ -277,7 +284,7 @@ impl WasiStateBuilder { /// Overwrite the default WASI `stdout`, if you want to hold on to the /// original `stdout` use [`WasiFs::swap_file`] after building. - pub fn stdout(&mut self, new_file: Box) -> &mut Self { + pub fn stdout(&mut self, new_file: Box) -> &mut Self { self.stdout_override = Some(new_file); self @@ -285,7 +292,7 @@ impl WasiStateBuilder { /// Overwrite the default WASI `stderr`, if you want to hold on to the /// original `stderr` use [`WasiFs::swap_file`] after building. - pub fn stderr(&mut self, new_file: Box) -> &mut Self { + pub fn stderr(&mut self, new_file: Box) -> &mut Self { self.stderr_override = Some(new_file); self @@ -293,7 +300,7 @@ impl WasiStateBuilder { /// Overwrite the default WASI `stdin`, if you want to hold on to the /// original `stdin` use [`WasiFs::swap_file`] after building. - pub fn stdin(&mut self, new_file: Box) -> &mut Self { + pub fn stdin(&mut self, new_file: Box) -> &mut Self { self.stdin_override = Some(new_file); self @@ -312,13 +319,27 @@ impl WasiStateBuilder { // TODO: improve ergonomics on this function pub fn setup_fs( &mut self, - setup_fs_fn: Box Result<(), String> + Send>, + setup_fs_fn: Box Result<(), String> + Send>, ) -> &mut Self { self.setup_fs_fn = Some(setup_fs_fn); self } + /// Sets a callback that will be invoked whenever the process yields execution. + /// + /// This is useful if the background tasks and/or callbacks are to be + /// executed whenever the WASM process goes idle + pub fn on_yield(&mut self, callback: F) -> &mut Self + where + F: Fn(&WasiThread) -> Result<(), WasiError>, + F: Send + Sync + 'static, + { + self.on_yield = Some(Arc::new(callback)); + + self + } + /// Consumes the [`WasiStateBuilder`] and produces a [`WasiState`] /// /// Returns the error from `WasiFs::new` if there's an error @@ -404,34 +425,50 @@ impl WasiStateBuilder { let fs_backing = self.fs_override.take().unwrap_or_else(default_fs_backing); // self.preopens are checked in [`PreopenDirBuilder::build`] - let mut wasi_fs = WasiFs::new_with_preopen(&self.preopens, &self.vfs_preopens, fs_backing) + let inodes = RwLock::new(crate::state::WasiInodes { + arena: Arena::new(), + orphan_fds: HashMap::new(), + }); + let wasi_fs = { + let mut inodes = inodes.write().unwrap(); + + // self.preopens are checked in [`PreopenDirBuilder::build`] + let mut wasi_fs = WasiFs::new_with_preopen( + inodes.deref_mut(), + &self.preopens, + &self.vfs_preopens, + fs_backing, + ) .map_err(WasiStateCreationError::WasiFsCreationError)?; - // set up the file system, overriding base files and calling the setup function - if let Some(stdin_override) = self.stdin_override.take() { - wasi_fs - .swap_file(__WASI_STDIN_FILENO, stdin_override) - .map_err(WasiStateCreationError::FileSystemError)?; - } + // set up the file system, overriding base files and calling the setup function + if let Some(stdin_override) = self.stdin_override.take() { + wasi_fs + .swap_file(inodes.deref(), __WASI_STDIN_FILENO, stdin_override) + .map_err(WasiStateCreationError::FileSystemError)?; + } - if let Some(stdout_override) = self.stdout_override.take() { - wasi_fs - .swap_file(__WASI_STDOUT_FILENO, stdout_override) - .map_err(WasiStateCreationError::FileSystemError)?; - } + if let Some(stdout_override) = self.stdout_override.take() { + wasi_fs + .swap_file(inodes.deref(), __WASI_STDOUT_FILENO, stdout_override) + .map_err(WasiStateCreationError::FileSystemError)?; + } - if let Some(stderr_override) = self.stderr_override.take() { - wasi_fs - .swap_file(__WASI_STDERR_FILENO, stderr_override) - .map_err(WasiStateCreationError::FileSystemError)?; - } + if let Some(stderr_override) = self.stderr_override.take() { + wasi_fs + .swap_file(inodes.deref(), __WASI_STDERR_FILENO, stderr_override) + .map_err(WasiStateCreationError::FileSystemError)?; + } - if let Some(f) = &self.setup_fs_fn { - f(&mut wasi_fs).map_err(WasiStateCreationError::WasiFsSetupError)?; - } + if let Some(f) = &self.setup_fs_fn { + f(inodes.deref_mut(), &mut wasi_fs).map_err(WasiStateCreationError::WasiFsSetupError)?; + } + wasi_fs + }; Ok(WasiState { fs: wasi_fs, + inodes, args: self.args.clone(), envs: self .envs @@ -461,7 +498,9 @@ impl WasiStateBuilder { pub fn finalize(&mut self) -> Result { let state = self.build()?; - Ok(WasiEnv::new(state)) + let mut env = WasiEnv::new(state); + env.on_yield = self.on_yield.clone(); + Ok(env) } } diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 10212563715..aa8a2d624b6 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -21,6 +21,7 @@ mod types; pub use self::builder::*; pub use self::types::*; use crate::syscalls::types::*; +use crate::utils::map_io_err; use generational_arena::Arena; pub use generational_arena::Index as Inode; #[cfg(feature = "enable-serde")] @@ -28,11 +29,15 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::{ borrow::Borrow, - cell::Cell, io::Write, + ops::{Deref, DerefMut}, path::{Path, PathBuf}, + sync::{ + atomic::{AtomicU32, AtomicU64, Ordering}, + RwLock, RwLockReadGuard, RwLockWriteGuard, + }, }; -use tracing::debug; +use tracing::{debug, trace}; use wasmer_vfs::{FileSystem, FsError, OpenOptions, VirtualFile}; @@ -62,10 +67,59 @@ pub const MAX_SYMLINKS: u32 = 128; #[derive(Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct InodeVal { - pub stat: __wasi_filestat_t, + pub stat: RwLock<__wasi_filestat_t>, pub is_preopened: bool, pub name: String, - pub kind: Kind, + pub kind: RwLock, +} + +impl InodeVal { + pub fn read(&self) -> RwLockReadGuard { + self.kind.read().unwrap() + } + + pub fn write(&self) -> RwLockWriteGuard { + self.kind.write().unwrap() + } +} + +#[derive(Debug)] +pub struct InodeValFileReadGuard<'a> { + pub(crate) guard: RwLockReadGuard<'a, Kind>, +} + +impl<'a> Deref for InodeValFileReadGuard<'a> { + type Target = Option>; + fn deref(&self) -> &Self::Target { + if let Kind::File { handle, .. } = self.guard.deref() { + return handle; + } + unreachable!() + } +} + +#[derive(Debug)] +pub struct InodeValFileWriteGuard<'a> { + pub(crate) guard: RwLockWriteGuard<'a, Kind>, +} + +impl<'a> Deref for InodeValFileWriteGuard<'a> { + type Target = Option>; + fn deref(&self) -> &Self::Target { + if let Kind::File { handle, .. } = self.guard.deref() { + return handle; + } + unreachable!() + } +} + +impl<'a> DerefMut for InodeValFileWriteGuard<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + if let Kind::File { handle, .. } = self.guard.deref_mut() { + return handle; + } + unreachable!() + } } /// The core of the filesystem abstraction. Includes directories, @@ -75,7 +129,7 @@ pub struct InodeVal { pub enum Kind { File { /// The open file, if it's open - handle: Option>, + handle: Option>, /// The path on the host system where the file is located /// This is deprecated and will be removed soon path: PathBuf, @@ -120,7 +174,7 @@ pub enum Kind { }, } -#[derive(Debug)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Fd { pub rights: __wasi_rights_t, @@ -154,20 +208,136 @@ impl Fd { pub const CREATE: u16 = 16; } +#[derive(Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct WasiInodes { + pub arena: Arena, + pub orphan_fds: HashMap, +} + +impl WasiInodes { + /// gets either a normal inode or an orphaned inode + pub fn get_inodeval( + &self, + inode: generational_arena::Index, + ) -> Result<&InodeVal, __wasi_errno_t> { + if let Some(iv) = self.arena.get(inode) { + Ok(iv) + } else { + self.orphan_fds.get(&inode).ok_or(__WASI_EBADF) + } + } + + /// gets either a normal inode or an orphaned inode + pub fn get_inodeval_mut( + &mut self, + inode: generational_arena::Index, + ) -> Result<&mut InodeVal, __wasi_errno_t> { + if let Some(iv) = self.arena.get_mut(inode) { + Ok(iv) + } else { + self.orphan_fds.get_mut(&inode).ok_or(__WASI_EBADF) + } + } + + /// Get the `VirtualFile` object at stdout + pub fn stdout( + &self, + fd_map: &RwLock>, + ) -> Result { + self.std_dev_get(fd_map, __WASI_STDOUT_FILENO) + } + /// Get the `VirtualFile` object at stdout mutably + pub fn stdout_mut( + &self, + fd_map: &RwLock>, + ) -> Result { + self.std_dev_get_mut(fd_map, __WASI_STDOUT_FILENO) + } + + /// Get the `VirtualFile` object at stderr + pub fn stderr( + &self, + fd_map: &RwLock>, + ) -> Result { + self.std_dev_get(fd_map, __WASI_STDERR_FILENO) + } + /// Get the `VirtualFile` object at stderr mutably + pub fn stderr_mut( + &self, + fd_map: &RwLock>, + ) -> Result { + self.std_dev_get_mut(fd_map, __WASI_STDERR_FILENO) + } + + /// Get the `VirtualFile` object at stdin + pub fn stdin( + &self, + fd_map: &RwLock>, + ) -> Result { + self.std_dev_get(fd_map, __WASI_STDIN_FILENO) + } + /// Get the `VirtualFile` object at stdin mutably + pub fn stdin_mut( + &self, + fd_map: &RwLock>, + ) -> Result { + self.std_dev_get_mut(fd_map, __WASI_STDIN_FILENO) + } + + /// Internal helper function to get a standard device handle. + /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. + fn std_dev_get( + &self, + fd_map: &RwLock>, + fd: __wasi_fd_t, + ) -> Result { + if let Some(fd) = fd_map.read().unwrap().get(&fd) { + let guard = self.arena[fd.inode].read(); + if let Kind::File { .. } = guard.deref() { + Ok(InodeValFileReadGuard { guard }) + } else { + // Our public API should ensure that this is not possible + unreachable!("Non-file found in standard device location") + } + } else { + // this should only trigger if we made a mistake in this crate + Err(FsError::NoDevice) + } + } + /// Internal helper function to mutably get a standard device handle. + /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. + fn std_dev_get_mut( + &self, + fd_map: &RwLock>, + fd: __wasi_fd_t, + ) -> Result { + if let Some(fd) = fd_map.read().unwrap().get(&fd) { + let guard = self.arena[fd.inode].write(); + if let Kind::File { .. } = guard.deref() { + Ok(InodeValFileWriteGuard { guard }) + } else { + // Our public API should ensure that this is not possible + unreachable!("Non-file found in standard device location") + } + } else { + // this should only trigger if we made a mistake in this crate + Err(FsError::NoDevice) + } + } +} + /// Warning, modifying these fields directly may cause invariants to break and /// should be considered unsafe. These fields may be made private in a future release #[derive(Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct WasiFs { //pub repo: Repo, - pub preopen_fds: Vec, + pub preopen_fds: RwLock>, pub name_map: HashMap, - pub inodes: Arena, - pub fd_map: HashMap, - pub next_fd: Cell, - inode_counter: Cell, - /// for fds still open after the file has been deleted - pub orphan_fds: HashMap, + pub fd_map: RwLock>, + pub next_fd: AtomicU32, + inode_counter: AtomicU64, #[cfg_attr(feature = "enable-serde", serde(skip, default = "default_fs_backing"))] pub fs_backing: Box, } @@ -224,11 +394,12 @@ impl FileSystem for FallbackFileSystem { impl WasiFs { /// Created for the builder API. like `new` but with more information pub(crate) fn new_with_preopen( + inodes: &mut WasiInodes, preopens: &[PreopenedDir], vfs_preopens: &[String], fs_backing: Box, ) -> Result { - let (mut wasi_fs, root_inode) = Self::new_init(fs_backing)?; + let (wasi_fs, root_inode) = Self::new_init(fs_backing, inodes)?; for preopen_name in vfs_preopens { let kind = Kind::Dir { @@ -250,7 +421,7 @@ impl WasiFs { | __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_SHUTDOWN; let inode = wasi_fs - .create_inode(kind, true, preopen_name.clone()) + .create_inode(inodes, kind, true, preopen_name.clone()) .map_err(|e| { format!( "Failed to create inode for preopened dir (name `{}`): WASI error code: {}", @@ -261,17 +432,20 @@ impl WasiFs { let fd = wasi_fs .create_fd(rights, rights, 0, fd_flags, inode) .map_err(|e| format!("Could not open fd for file {:?}: {}", preopen_name, e))?; - if let Kind::Root { entries } = &mut wasi_fs.inodes[root_inode].kind { - let existing_entry = entries.insert(preopen_name.clone(), inode); - if existing_entry.is_some() { - return Err(format!( - "Found duplicate entry for alias `{}`", - preopen_name - )); + { + let mut guard = inodes.arena[root_inode].write(); + if let Kind::Root { entries } = guard.deref_mut() { + let existing_entry = entries.insert(preopen_name.clone(), inode); + if existing_entry.is_some() { + return Err(format!( + "Found duplicate entry for alias `{}`", + preopen_name + )); + } + assert!(existing_entry.is_none()) } - assert!(existing_entry.is_none()) } - wasi_fs.preopen_fds.push(fd); + wasi_fs.preopen_fds.write().unwrap().push(fd); } for PreopenedDir { @@ -343,15 +517,16 @@ impl WasiFs { | __WASI_RIGHT_PATH_CREATE_FILE | __WASI_RIGHT_PATH_LINK_TARGET | __WASI_RIGHT_PATH_OPEN - | __WASI_RIGHT_PATH_RENAME_TARGET; + | __WASI_RIGHT_PATH_RENAME_TARGET + | __WASI_RIGHT_PATH_SYMLINK; } rights }; let inode = if let Some(alias) = &alias { - wasi_fs.create_inode(kind, true, alias.clone()) + wasi_fs.create_inode(inodes, kind, true, alias.clone()) } else { - wasi_fs.create_inode(kind, true, path.to_string_lossy().into_owned()) + wasi_fs.create_inode(inodes, kind, true, path.to_string_lossy().into_owned()) } .map_err(|e| { format!( @@ -376,19 +551,22 @@ impl WasiFs { let fd = wasi_fs .create_fd(rights, rights, 0, fd_flags, inode) .map_err(|e| format!("Could not open fd for file {:?}: {}", path, e))?; - if let Kind::Root { entries } = &mut wasi_fs.inodes[root_inode].kind { - let key = if let Some(alias) = &alias { - alias.clone() - } else { - path.to_string_lossy().into_owned() - }; - let existing_entry = entries.insert(key.clone(), inode); - if existing_entry.is_some() { - return Err(format!("Found duplicate entry for alias `{}`", key)); + { + let mut guard = inodes.arena[root_inode].write(); + if let Kind::Root { entries } = guard.deref_mut() { + let key = if let Some(alias) = &alias { + alias.clone() + } else { + path.to_string_lossy().into_owned() + }; + let existing_entry = entries.insert(key.clone(), inode); + if existing_entry.is_some() { + return Err(format!("Found duplicate entry for alias `{}`", key)); + } + assert!(existing_entry.is_none()) } - assert!(existing_entry.is_none()) } - wasi_fs.preopen_fds.push(fd); + wasi_fs.preopen_fds.write().unwrap().push(fd); } Ok(wasi_fs) @@ -396,22 +574,22 @@ impl WasiFs { /// Private helper function to init the filesystem, called in `new` and /// `new_with_preopen` - fn new_init(fs_backing: Box) -> Result<(Self, Inode), String> { + fn new_init( + fs_backing: Box, + inodes: &mut WasiInodes, + ) -> Result<(Self, Inode), String> { debug!("Initializing WASI filesystem"); - let inodes = Arena::new(); - let mut wasi_fs = Self { - preopen_fds: vec![], + let wasi_fs = Self { + preopen_fds: RwLock::new(vec![]), name_map: HashMap::new(), - inodes, - fd_map: HashMap::new(), - next_fd: Cell::new(3), - inode_counter: Cell::new(1024), - orphan_fds: HashMap::new(), + fd_map: RwLock::new(HashMap::new()), + next_fd: AtomicU32::new(3), + inode_counter: AtomicU64::new(1024), fs_backing, }; - wasi_fs.create_stdin(); - wasi_fs.create_stdout(); - wasi_fs.create_stderr(); + wasi_fs.create_stdin(inodes); + wasi_fs.create_stdout(inodes); + wasi_fs.create_stderr(inodes); // create virtual root let root_inode = { @@ -433,83 +611,20 @@ impl WasiFs { & (!__WASI_RIGHT_PATH_SYMLINK) & (!__WASI_RIGHT_PATH_UNLINK_FILE) & (!__WASI_RIGHT_PATH_REMOVE_DIRECTORY)*/; - let inode = wasi_fs.create_virtual_root(); + let inode = wasi_fs.create_virtual_root(inodes); let fd = wasi_fs .create_fd(root_rights, root_rights, 0, Fd::READ, inode) .map_err(|e| format!("Could not create root fd: {}", e))?; - wasi_fs.preopen_fds.push(fd); + wasi_fs.preopen_fds.write().unwrap().push(fd); inode }; Ok((wasi_fs, root_inode)) } - /// Get the `VirtualFile` object at stdout - pub fn stdout(&self) -> Result<&Option>, FsError> { - self.std_dev_get(__WASI_STDOUT_FILENO) - } - /// Get the `VirtualFile` object at stdout mutably - pub fn stdout_mut(&mut self) -> Result<&mut Option>, FsError> { - self.std_dev_get_mut(__WASI_STDOUT_FILENO) - } - - /// Get the `VirtualFile` object at stderr - pub fn stderr(&self) -> Result<&Option>, FsError> { - self.std_dev_get(__WASI_STDERR_FILENO) - } - /// Get the `VirtualFile` object at stderr mutably - pub fn stderr_mut(&mut self) -> Result<&mut Option>, FsError> { - self.std_dev_get_mut(__WASI_STDERR_FILENO) - } - - /// Get the `VirtualFile` object at stdin - pub fn stdin(&self) -> Result<&Option>, FsError> { - self.std_dev_get(__WASI_STDIN_FILENO) - } - /// Get the `VirtualFile` object at stdin mutably - pub fn stdin_mut(&mut self) -> Result<&mut Option>, FsError> { - self.std_dev_get_mut(__WASI_STDIN_FILENO) - } - - /// Internal helper function to get a standard device handle. - /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. - fn std_dev_get(&self, fd: __wasi_fd_t) -> Result<&Option>, FsError> { - if let Some(fd) = self.fd_map.get(&fd) { - if let Kind::File { ref handle, .. } = self.inodes[fd.inode].kind { - Ok(handle) - } else { - // Our public API should ensure that this is not possible - unreachable!("Non-file found in standard device location") - } - } else { - // this should only trigger if we made a mistake in this crate - Err(FsError::NoDevice) - } - } - /// Internal helper function to mutably get a standard device handle. - /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. - fn std_dev_get_mut( - &mut self, - fd: __wasi_fd_t, - ) -> Result<&mut Option>, FsError> { - if let Some(fd) = self.fd_map.get_mut(&fd) { - if let Kind::File { ref mut handle, .. } = self.inodes[fd.inode].kind { - Ok(handle) - } else { - // Our public API should ensure that this is not possible - unreachable!("Non-file found in standard device location") - } - } else { - // this should only trigger if we made a mistake in this crate - Err(FsError::NoDevice) - } - } - /// Returns the next available inode index for creating a new inode. - fn get_next_inode_index(&mut self) -> u64 { - let next = self.inode_counter.get(); - self.inode_counter.set(next + 1); - next + fn get_next_inode_index(&self) -> u64 { + self.inode_counter.fetch_add(1, Ordering::AcqRel) } /// This function is like create dir all, but it also opens it. @@ -524,22 +639,23 @@ impl WasiFs { #[allow(dead_code)] pub unsafe fn open_dir_all( &mut self, + inodes: &mut WasiInodes, base: __wasi_fd_t, name: String, rights: __wasi_rights_t, rights_inheriting: __wasi_rights_t, flags: __wasi_fdflags_t, ) -> Result<__wasi_fd_t, FsError> { - let base_fd = self.get_fd(base).map_err(fs_error_from_wasi_err)?; // TODO: check permissions here? probably not, but this should be // an explicit choice, so justify it in a comment when we remove this one - let mut cur_inode = base_fd.inode; + let mut cur_inode = self.get_fd_inode(base).map_err(fs_error_from_wasi_err)?; let path: &Path = Path::new(&name); //let n_components = path.components().count(); for c in path.components() { let segment_name = c.as_os_str().to_string_lossy().to_string(); - match &self.inodes[cur_inode].kind { + let guard = inodes.arena[cur_inode].read(); + match guard.deref() { Kind::Dir { ref entries, .. } | Kind::Root { ref entries } => { if let Some(_entry) = entries.get(&segment_name) { // TODO: this should be fixed @@ -552,19 +668,27 @@ impl WasiFs { entries: HashMap::new(), }; - let inode = - self.create_inode_with_default_stat(kind, false, segment_name.clone()); + drop(guard); + let inode = self.create_inode_with_default_stat( + inodes, + kind, + false, + segment_name.clone(), + ); + // reborrow to insert - match &mut self.inodes[cur_inode].kind { - Kind::Dir { - ref mut entries, .. - } - | Kind::Root { ref mut entries } => { - entries.insert(segment_name, inode); + { + let mut guard = inodes.arena[cur_inode].write(); + match guard.deref_mut() { + Kind::Dir { + ref mut entries, .. + } + | Kind::Root { ref mut entries } => { + entries.insert(segment_name, inode); + } + _ => unreachable!("Dir or Root became not Dir or Root"), } - _ => unreachable!("Dir or Root became not Dir or Root"), } - cur_inode = inode; } _ => return Err(FsError::BaseNotDirectory), @@ -588,20 +712,21 @@ impl WasiFs { #[allow(dead_code)] pub fn open_file_at( &mut self, + inodes: &mut WasiInodes, base: __wasi_fd_t, - file: Box, + file: Box, open_flags: u16, name: String, rights: __wasi_rights_t, rights_inheriting: __wasi_rights_t, flags: __wasi_fdflags_t, ) -> Result<__wasi_fd_t, FsError> { - let base_fd = self.get_fd(base).map_err(fs_error_from_wasi_err)?; // TODO: check permissions here? probably not, but this should be // an explicit choice, so justify it in a comment when we remove this one - let base_inode = base_fd.inode; + let base_inode = self.get_fd_inode(base).map_err(fs_error_from_wasi_err)?; - match &self.inodes[base_inode].kind { + let guard = inodes.arena[base_inode].read(); + match guard.deref() { Kind::Dir { ref entries, .. } | Kind::Root { ref entries } => { if let Some(_entry) = entries.get(&name) { // TODO: eventually change the logic here to allow overwrites @@ -611,21 +736,25 @@ impl WasiFs { let kind = Kind::File { handle: Some(file), path: PathBuf::from(""), - fd: Some(self.next_fd.get()), + fd: Some(self.next_fd.load(Ordering::Acquire)), }; + drop(guard); let inode = self - .create_inode(kind, false, name.clone()) + .create_inode(inodes, kind, false, name.clone()) .map_err(|_| FsError::IOError)?; - // reborrow to insert - match &mut self.inodes[base_inode].kind { - Kind::Dir { - ref mut entries, .. - } - | Kind::Root { ref mut entries } => { - entries.insert(name, inode); + + { + let mut guard = inodes.arena[base_inode].write(); + match guard.deref_mut() { + Kind::Dir { + ref mut entries, .. + } + | Kind::Root { ref mut entries } => { + entries.insert(name, inode); + } + _ => unreachable!("Dir or Root became not Dir or Root"), } - _ => unreachable!("Dir or Root became not Dir or Root"), } self.create_fd(rights, rights_inheriting, flags, open_flags, inode) @@ -640,26 +769,29 @@ impl WasiFs { /// TODO: add examples #[allow(dead_code)] pub fn swap_file( - &mut self, + &self, + inodes: &WasiInodes, fd: __wasi_fd_t, - file: Box, - ) -> Result>, FsError> { + file: Box, + ) -> Result>, FsError> { let mut ret = Some(file); match fd { __WASI_STDIN_FILENO => { - std::mem::swap(self.stdin_mut()?, &mut ret); + let mut target = inodes.stdin_mut(&self.fd_map)?; + std::mem::swap(target.deref_mut(), &mut ret); } __WASI_STDOUT_FILENO => { - std::mem::swap(self.stdout_mut()?, &mut ret); + let mut target = inodes.stdout_mut(&self.fd_map)?; + std::mem::swap(target.deref_mut(), &mut ret); } __WASI_STDERR_FILENO => { - std::mem::swap(self.stderr_mut()?, &mut ret); + let mut target = inodes.stderr_mut(&self.fd_map)?; + std::mem::swap(target.deref_mut(), &mut ret); } _ => { - let base_fd = self.get_fd(fd).map_err(fs_error_from_wasi_err)?; - let base_inode = base_fd.inode; - - match &mut self.inodes[base_inode].kind { + let base_inode = self.get_fd_inode(fd).map_err(fs_error_from_wasi_err)?; + let mut guard = inodes.arena[base_inode].write(); + match guard.deref_mut() { Kind::File { ref mut handle, .. } => { std::mem::swap(handle, &mut ret); } @@ -673,15 +805,19 @@ impl WasiFs { /// refresh size from filesystem pub(crate) fn filestat_resync_size( - &mut self, + &self, + inodes: &WasiInodes, fd: __wasi_fd_t, ) -> Result<__wasi_filesize_t, __wasi_errno_t> { - let fd = self.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)?; - match &mut self.inodes[fd.inode].kind { + let inode = self.get_fd_inode(fd)?; + let mut guard = inodes.arena[inode].write(); + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(h) = handle { let new_size = h.size(); - self.inodes[fd.inode].stat.st_size = new_size; + drop(guard); + + inodes.arena[inode].stat.write().unwrap().st_size = new_size; Ok(new_size as __wasi_filesize_t) } else { Err(__WASI_EBADF) @@ -706,7 +842,8 @@ impl WasiFs { /// /// TODO: write more tests for this code fn get_inode_at_path_inner( - &mut self, + &self, + inodes: &mut WasiInodes, base: __wasi_fd_t, path: &str, mut symlink_count: u32, @@ -716,10 +853,9 @@ impl WasiFs { return Err(__WASI_EMLINK); } - let base_dir = self.get_fd(base)?; let path: &Path = Path::new(path); - let mut cur_inode = base_dir.inode; + let mut cur_inode = self.get_fd_inode(base)?; let n_components = path.components().count(); // TODO: rights checks 'path_iter: for (i, component) in path.components().enumerate() { @@ -728,7 +864,8 @@ impl WasiFs { // for each component traverse file structure // loading inodes as necessary 'symlink_resolution: while symlink_count < MAX_SYMLINKS { - match &mut self.inodes[cur_inode].kind { + let mut guard = inodes.arena[cur_inode].write(); + match guard.deref_mut() { Kind::Buffer { .. } => unimplemented!("state::get_inode_at_path for buffers"), Kind::Dir { ref mut entries, @@ -788,11 +925,11 @@ impl WasiFs { } } else if file_type.is_symlink() { should_insert = false; - let link_value = file.read_link().ok().ok_or(__WASI_EIO)?; + let link_value = file.read_link().map_err(map_io_err)?; debug!("attempting to decompose path {:?}", link_value); let (pre_open_dir_fd, relative_path) = if link_value.is_relative() { - self.path_into_pre_open_and_relative_path(&file)? + self.path_into_pre_open_and_relative_path(inodes, &file)? } else { unimplemented!("Absolute symlinks are not yet supported"); }; @@ -828,7 +965,9 @@ impl WasiFs { path: file.clone(), fd: None, }; + drop(guard); let new_inode = self.create_inode_with_stat( + inodes, kind, false, file.to_string_lossy().to_string(), @@ -837,9 +976,11 @@ impl WasiFs { ..__wasi_filestat_t::default() }, ); + + let mut guard = inodes.arena[cur_inode].write(); if let Kind::Dir { ref mut entries, .. - } = &mut self.inodes[cur_inode].kind + } = guard.deref_mut() { entries.insert( component.as_os_str().to_string_lossy().to_string(), @@ -857,12 +998,18 @@ impl WasiFs { unimplemented!("state::get_inode_at_path unknown file type: not file, directory, or symlink"); }; - let new_inode = - self.create_inode(kind, false, file.to_string_lossy().to_string())?; + drop(guard); + let new_inode = self.create_inode( + inodes, + kind, + false, + file.to_string_lossy().to_string(), + )?; if should_insert { + let mut guard = inodes.arena[cur_inode].write(); if let Kind::Dir { ref mut entries, .. - } = &mut self.inodes[cur_inode].kind + } = guard.deref_mut() { entries.insert( component.as_os_str().to_string_lossy().to_string(), @@ -917,7 +1064,9 @@ impl WasiFs { base.to_string_lossy().to_string() }; debug!("Following symlink recursively"); + drop(guard); let symlink_inode = self.get_inode_at_path_inner( + inodes, new_base_dir, &new_path, symlink_count + 1, @@ -926,7 +1075,8 @@ impl WasiFs { cur_inode = symlink_inode; // if we're at the very end and we found a file, then we're done // TODO: figure out if this should also happen for directories? - if let Kind::File { .. } = &self.inodes[cur_inode].kind { + let guard = inodes.arena[cur_inode].read(); + if let Kind::File { .. } = guard.deref() { // check if on last step if last_component { break 'symlink_resolution; @@ -953,6 +1103,7 @@ impl WasiFs { /// In the case of a tie, the later preopened fd is preferred. fn path_into_pre_open_and_relative_path<'path>( &self, + inodes: &WasiInodes, path: &'path Path, ) -> Result<(__wasi_fd_t, &'path Path), __wasi_errno_t> { enum BaseFdAndRelPath<'a> { @@ -974,9 +1125,11 @@ impl WasiFs { } let mut res = BaseFdAndRelPath::None; // for each preopened directory - for po_fd in &self.preopen_fds { - let po_inode = self.fd_map[po_fd].inode; - let po_path = match &self.inodes[po_inode].kind { + let preopen_fds = self.preopen_fds.read().unwrap(); + for po_fd in preopen_fds.deref() { + let po_inode = self.fd_map.read().unwrap()[po_fd].inode; + let guard = inodes.arena[po_inode].read(); + let po_path = match guard.deref() { Kind::Dir { path, .. } => &**path, Kind::Root { .. } => Path::new("/"), _ => unreachable!("Preopened FD that's not a directory or the root"), @@ -1007,17 +1160,18 @@ impl WasiFs { /// expects inode to point to a directory pub(crate) fn path_depth_from_fd( &self, + inodes: &WasiInodes, fd: __wasi_fd_t, inode: Inode, ) -> Result { let mut counter = 0; - let base_fd = self.get_fd(fd)?; - let base_inode = base_fd.inode; + let base_inode = self.get_fd_inode(fd)?; let mut cur_inode = inode; while cur_inode != base_inode { counter += 1; - match &self.inodes[cur_inode].kind { + let guard = inodes.arena[cur_inode].read(); + match guard.deref() { Kind::Dir { parent, .. } => { if let Some(p) = parent { cur_inode = *p; @@ -1037,18 +1191,20 @@ impl WasiFs { // symlink so // This will be resolved when we have tests asserting the correct behavior pub(crate) fn get_inode_at_path( - &mut self, + &self, + inodes: &mut WasiInodes, base: __wasi_fd_t, path: &str, follow_symlinks: bool, ) -> Result { - self.get_inode_at_path_inner(base, path, 0, follow_symlinks) + self.get_inode_at_path_inner(inodes, base, path, 0, follow_symlinks) } /// Returns the parent Dir or Root that the file at a given path is in and the file name /// stripped off pub(crate) fn get_parent_inode_at_path( - &mut self, + &self, + inodes: &mut WasiInodes, base: __wasi_fd_t, path: &Path, follow_symlinks: bool, @@ -1064,31 +1220,45 @@ impl WasiFs { for comp in components.rev() { parent_dir.push(comp); } - self.get_inode_at_path(base, &parent_dir.to_string_lossy(), follow_symlinks) + self.get_inode_at_path(inodes, base, &parent_dir.to_string_lossy(), follow_symlinks) .map(|v| (v, new_entity_name)) } - pub fn get_fd(&self, fd: __wasi_fd_t) -> Result<&Fd, __wasi_errno_t> { - self.fd_map.get(&fd).ok_or(__WASI_EBADF) + pub fn get_fd(&self, fd: __wasi_fd_t) -> Result { + self.fd_map + .read() + .unwrap() + .get(&fd) + .ok_or(__WASI_EBADF) + .map(|a| a.clone()) } - /// gets either a normal inode or an orphaned inode - pub fn get_inodeval_mut(&mut self, fd: __wasi_fd_t) -> Result<&mut InodeVal, __wasi_errno_t> { - let inode = self.get_fd(fd)?.inode; - if let Some(iv) = self.inodes.get_mut(inode) { - Ok(iv) - } else { - self.orphan_fds.get_mut(&inode).ok_or(__WASI_EBADF) - } + pub fn get_fd_inode( + &self, + fd: __wasi_fd_t, + ) -> Result { + self.fd_map + .read() + .unwrap() + .get(&fd) + .ok_or(__WASI_EBADF) + .map(|a| a.inode) } - pub fn filestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_filestat_t, __wasi_errno_t> { - let fd = self.get_fd(fd)?; - - Ok(self.inodes[fd.inode].stat) + pub fn filestat_fd( + &self, + inodes: &WasiInodes, + fd: __wasi_fd_t, + ) -> Result<__wasi_filestat_t, __wasi_errno_t> { + let inode = self.get_fd_inode(fd)?; + Ok(inodes.arena[inode].stat.read().unwrap().deref().clone()) } - pub fn fdstat(&self, fd: __wasi_fd_t) -> Result<__wasi_fdstat_t, __wasi_errno_t> { + pub fn fdstat( + &self, + inodes: &WasiInodes, + fd: __wasi_fd_t, + ) -> Result<__wasi_fdstat_t, __wasi_errno_t> { match fd { __WASI_STDIN_FILENO => { return Ok(__wasi_fdstat_t { @@ -1126,11 +1296,11 @@ impl WasiFs { _ => (), } let fd = self.get_fd(fd)?; - debug!("fdstat: {:?}", fd); + let guard = inodes.arena[fd.inode].read(); Ok(__wasi_fdstat_t { - fs_filetype: match self.inodes[fd.inode].kind { + fs_filetype: match guard.deref() { Kind::File { .. } => __WASI_FILETYPE_REGULAR_FILE, Kind::Dir { .. } => __WASI_FILETYPE_DIRECTORY, Kind::Symlink { .. } => __WASI_FILETYPE_SYMBOLIC_LINK, @@ -1142,11 +1312,15 @@ impl WasiFs { }) } - pub fn prestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_prestat_t, __wasi_errno_t> { - let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?; + pub fn prestat_fd( + &self, + inodes: &WasiInodes, + fd: __wasi_fd_t, + ) -> Result<__wasi_prestat_t, __wasi_errno_t> { + let inode = self.get_fd_inode(fd)?; + trace!("in prestat_fd {:?}", self.get_fd(fd)?); - debug!("in prestat_fd {:?}", fd); - let inode_val = &self.inodes[fd.inode]; + let inode_val = &inodes.arena[inode]; if inode_val.is_preopened { Ok(__wasi_prestat_t { @@ -1162,35 +1336,35 @@ impl WasiFs { } } - pub fn flush(&mut self, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> { + pub fn flush(&self, inodes: &WasiInodes, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> { match fd { __WASI_STDIN_FILENO => (), - __WASI_STDOUT_FILENO => self - .stdout_mut() + __WASI_STDOUT_FILENO => inodes + .stdout_mut(&self.fd_map) .map_err(fs_error_into_wasi_err)? .as_mut() - .and_then(|f| f.flush().ok()) - .ok_or(__WASI_EIO)?, - __WASI_STDERR_FILENO => self - .stderr_mut() + .and_then(|f| Some(f.flush().map_err(map_io_err))) + .unwrap_or_else(|| Err(__WASI_EIO))?, + __WASI_STDERR_FILENO => inodes + .stderr_mut(&self.fd_map) .map_err(fs_error_into_wasi_err)? .as_mut() .and_then(|f| f.flush().ok()) .ok_or(__WASI_EIO)?, _ => { - let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?; + let fd = self.get_fd(fd)?; if fd.rights & __WASI_RIGHT_FD_DATASYNC == 0 { return Err(__WASI_EACCES); } - let inode = &mut self.inodes[fd.inode]; - - match &mut inode.kind { - Kind::File { - handle: Some(file), .. - } => file.flush().map_err(|_| __WASI_EIO)?, - Kind::File { handle: None, .. } => { - return Err(__WASI_EIO); + let mut guard = inodes.arena[fd.inode].write(); + match guard.deref_mut() { + Kind::File { handle, .. } => { + if let Some(file) = handle { + file.flush().map_err(|_| __WASI_EIO)? + } else { + return Err(__WASI_EIO); + } } // TODO: verify this behavior Kind::Dir { .. } => return Err(__WASI_EISDIR), @@ -1205,29 +1379,32 @@ impl WasiFs { /// Creates an inode and inserts it given a Kind and some extra data pub(crate) fn create_inode( - &mut self, + &self, + inodes: &mut WasiInodes, kind: Kind, is_preopened: bool, name: String, ) -> Result { - let stat = self.get_stat_for_kind(&kind).ok_or(__WASI_EIO)?; - Ok(self.create_inode_with_stat(kind, is_preopened, name, stat)) + let stat = self.get_stat_for_kind(inodes, &kind)?; + Ok(self.create_inode_with_stat(inodes, kind, is_preopened, name, stat)) } /// Creates an inode and inserts it given a Kind, does not assume the file exists. pub(crate) fn create_inode_with_default_stat( - &mut self, + &self, + inodes: &mut WasiInodes, kind: Kind, is_preopened: bool, name: String, ) -> Inode { let stat = __wasi_filestat_t::default(); - self.create_inode_with_stat(kind, is_preopened, name, stat) + self.create_inode_with_stat(inodes, kind, is_preopened, name, stat) } /// Creates an inode with the given filestat and inserts it. pub(crate) fn create_inode_with_stat( - &mut self, + &self, + inodes: &mut WasiInodes, kind: Kind, is_preopened: bool, name: String, @@ -1235,25 +1412,24 @@ impl WasiFs { ) -> Inode { stat.st_ino = self.get_next_inode_index(); - self.inodes.insert(InodeVal { - stat, + inodes.arena.insert(InodeVal { + stat: RwLock::new(stat), is_preopened, name, - kind, + kind: RwLock::new(kind), }) } pub fn create_fd( - &mut self, + &self, rights: __wasi_rights_t, rights_inheriting: __wasi_rights_t, flags: __wasi_fdflags_t, open_flags: u16, inode: Inode, ) -> Result<__wasi_fd_t, __wasi_errno_t> { - let idx = self.next_fd.get(); - self.next_fd.set(idx + 1); - self.fd_map.insert( + let idx = self.next_fd.fetch_add(1, Ordering::AcqRel); + self.fd_map.write().unwrap().insert( idx, Fd { rights, @@ -1275,11 +1451,11 @@ impl WasiFs { /// # Safety /// - The caller must ensure that all references to the specified inode have /// been removed from the filesystem. - pub unsafe fn remove_inode(&mut self, inode: Inode) -> Option { - self.inodes.remove(inode) + pub unsafe fn remove_inode(&self, inodes: &mut WasiInodes, inode: Inode) -> Option { + inodes.arena.remove(inode) } - fn create_virtual_root(&mut self) -> Inode { + fn create_virtual_root(&self, inodes: &mut WasiInodes) -> Inode { let stat = __wasi_filestat_t { st_filetype: __WASI_FILETYPE_DIRECTORY, st_ino: self.get_next_inode_index(), @@ -1289,16 +1465,17 @@ impl WasiFs { entries: HashMap::new(), }; - self.inodes.insert(InodeVal { - stat, + inodes.arena.insert(InodeVal { + stat: RwLock::new(stat), is_preopened: true, name: "/".to_string(), - kind: root_kind, + kind: RwLock::new(root_kind), }) } - fn create_stdout(&mut self) { + fn create_stdout(&self, inodes: &mut WasiInodes) { self.create_std_dev_inner( + inodes, Box::new(Stdout::default()), "stdout", __WASI_STDOUT_FILENO, @@ -1306,8 +1483,9 @@ impl WasiFs { __WASI_FDFLAG_APPEND, ); } - fn create_stdin(&mut self) { + fn create_stdin(&self, inodes: &mut WasiInodes) { self.create_std_dev_inner( + inodes, Box::new(Stdin::default()), "stdin", __WASI_STDIN_FILENO, @@ -1315,8 +1493,9 @@ impl WasiFs { 0, ); } - fn create_stderr(&mut self) { + fn create_stderr(&self, inodes: &mut WasiInodes) { self.create_std_dev_inner( + inodes, Box::new(Stderr::default()), "stderr", __WASI_STDERR_FILENO, @@ -1326,8 +1505,9 @@ impl WasiFs { } fn create_std_dev_inner( - &mut self, - handle: Box, + &self, + inodes: &mut WasiInodes, + handle: Box, name: &'static str, raw_fd: __wasi_fd_t, rights: __wasi_rights_t, @@ -1343,13 +1523,15 @@ impl WasiFs { handle: Some(handle), path: "".into(), }; - let inode = self.inodes.insert(InodeVal { - stat, - is_preopened: true, - name: name.to_string(), - kind, - }); - self.fd_map.insert( + let inode = { + inodes.arena.insert(InodeVal { + stat: RwLock::new(stat), + is_preopened: true, + name: name.to_string(), + kind: RwLock::new(kind), + }) + }; + self.fd_map.write().unwrap().insert( raw_fd, Fd { rights, @@ -1363,11 +1545,15 @@ impl WasiFs { ); } - pub fn get_stat_for_kind(&self, kind: &Kind) -> Option<__wasi_filestat_t> { + pub fn get_stat_for_kind( + &self, + inodes: &WasiInodes, + kind: &Kind, + ) -> Result<__wasi_filestat_t, __wasi_errno_t> { let md = match kind { Kind::File { handle, path, .. } => match handle { Some(wf) => { - return Some(__wasi_filestat_t { + return Ok(__wasi_filestat_t { st_filetype: __WASI_FILETYPE_REGULAR_FILE, st_size: wf.size(), st_atim: wf.last_accessed(), @@ -1377,19 +1563,26 @@ impl WasiFs { ..__wasi_filestat_t::default() }) } - None => self.fs_backing.metadata(path).ok()?, + None => self + .fs_backing + .metadata(path) + .map_err(fs_error_into_wasi_err)?, }, - Kind::Dir { path, .. } => self.fs_backing.metadata(path).ok()?, + Kind::Dir { path, .. } => self + .fs_backing + .metadata(path) + .map_err(fs_error_into_wasi_err)?, Kind::Symlink { base_po_dir, path_to_symlink, .. } => { - let base_po_inode = &self.fd_map[base_po_dir].inode; - let base_po_inode_v = &self.inodes[*base_po_inode]; - match &base_po_inode_v.kind { + let base_po_inode = &self.fd_map.read().unwrap()[base_po_dir].inode; + let base_po_inode_v = &inodes.arena[*base_po_inode]; + let guard = base_po_inode_v.read(); + match guard.deref() { Kind::Root { .. } => { - self.fs_backing.symlink_metadata(path_to_symlink).ok()? + self.fs_backing.symlink_metadata(path_to_symlink).map_err(fs_error_into_wasi_err)? } Kind::Dir { path, .. } => { let mut real_path = path.clone(); @@ -1400,15 +1593,15 @@ impl WasiFs { // TODO: adjust size of symlink, too // for all paths adjusted think about this real_path.push(path_to_symlink); - self.fs_backing.symlink_metadata(&real_path).ok()? + self.fs_backing.symlink_metadata(&real_path).map_err(fs_error_into_wasi_err)? } // if this triggers, there's a bug in the symlink code _ => unreachable!("Symlink pointing to something that's not a directory as its base preopened directory"), } } - _ => return None, + _ => return Err(__WASI_EIO), }; - Some(__wasi_filestat_t { + Ok(__wasi_filestat_t { st_filetype: virtual_file_type_to_wasi_file_type(md.file_type()), st_size: md.len(), st_atim: md.accessed(), @@ -1419,11 +1612,17 @@ impl WasiFs { } /// Closes an open FD, handling all details such as FD being preopen - pub(crate) fn close_fd(&mut self, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> { - let inodeval_mut = self.get_inodeval_mut(fd)?; - let is_preopened = inodeval_mut.is_preopened; + pub(crate) fn close_fd( + &self, + inodes: &WasiInodes, + fd: __wasi_fd_t, + ) -> Result<(), __wasi_errno_t> { + let inode = self.get_fd_inode(fd)?; + let inodeval = inodes.get_inodeval(inode)?; + let is_preopened = inodeval.is_preopened; - match &mut inodeval_mut.kind { + let mut guard = inodeval.write(); + match guard.deref_mut() { Kind::File { ref mut handle, .. } => { let mut empty_handle = None; std::mem::swap(handle, &mut empty_handle); @@ -1436,22 +1635,27 @@ impl WasiFs { .to_string_lossy() .to_string(); if let Some(p) = *parent { - match &mut self.inodes[p].kind { + drop(guard); + let mut guard = inodes.arena[p].write(); + match guard.deref_mut() { Kind::Dir { entries, .. } | Kind::Root { entries } => { - self.fd_map.remove(&fd).unwrap(); + self.fd_map.write().unwrap().remove(&fd).unwrap(); if is_preopened { let mut idx = None; - for (i, po_fd) in self.preopen_fds.iter().enumerate() { - if *po_fd == fd { - idx = Some(i); - break; + { + let preopen_fds = self.preopen_fds.read().unwrap(); + for (i, po_fd) in preopen_fds.iter().enumerate() { + if *po_fd == fd { + idx = Some(i); + break; + } } } if let Some(i) = idx { // only remove entry properly if this is the original preopen FD // calling `path_open` can give you an fd to the same inode as a preopen fd entries.remove(&key); - self.preopen_fds.remove(i); + self.preopen_fds.write().unwrap().remove(i); // Maybe recursively closes fds if original preopen? } } @@ -1555,6 +1759,7 @@ impl WasiState { #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct WasiState { pub fs: WasiFs, + pub inodes: RwLock, pub args: Vec>, pub envs: Vec>, } diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index f20e92efcd7..f14ab1de92b 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -2,11 +2,12 @@ use crate::syscalls::types::*; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; -#[cfg(unix)] +#[cfg(all(unix, feature = "sys-poll"))] use std::convert::TryInto; use std::{ collections::VecDeque, io::{self, Read, Seek, Write}, + time::Duration, }; #[cfg(feature = "host-fs")] @@ -137,7 +138,7 @@ pub fn iterate_poll_events(pes: PollEventSet) -> PollEventIter { PollEventIter { pes, i: 0 } } -#[cfg(unix)] +#[cfg(all(unix, feature = "sys-poll"))] fn poll_event_set_to_platform_poll_events(mut pes: PollEventSet) -> i16 { let mut out = 0; for i in 0..16 { @@ -154,7 +155,7 @@ fn poll_event_set_to_platform_poll_events(mut pes: PollEventSet) -> i16 { out } -#[cfg(unix)] +#[cfg(all(unix, feature = "sys-poll"))] fn platform_poll_events_to_pollevent_set(mut num: i16) -> PollEventSet { let mut peb = PollEventBuilder::new(); for i in 0..16 { @@ -171,6 +172,7 @@ fn platform_poll_events_to_pollevent_set(mut num: i16) -> PollEventSet { peb.build() } +#[allow(dead_code)] impl PollEventBuilder { pub fn new() -> PollEventBuilder { PollEventBuilder { inner: 0 } @@ -186,11 +188,12 @@ impl PollEventBuilder { } } -#[cfg(unix)] +#[cfg(all(unix, feature = "sys-poll"))] pub(crate) fn poll( - selfs: &[&dyn VirtualFile], + selfs: &[&(dyn VirtualFile + Sync)], events: &[PollEventSet], seen_events: &mut [PollEventSet], + timeout: Duration, ) -> Result { if !(selfs.len() == events.len() && events.len() == seen_events.len()) { return Err(FsError::InvalidInput); @@ -205,7 +208,7 @@ pub(crate) fn poll( revents: 0, }) .collect::>(); - let result = unsafe { libc::poll(fds.as_mut_ptr(), selfs.len() as _, 1) }; + let result = unsafe { libc::poll(fds.as_mut_ptr(), selfs.len() as _, timeout.as_millis() as i32) }; if result < 0 { // TODO: check errno and return value @@ -219,13 +222,67 @@ pub(crate) fn poll( Ok(result.try_into().unwrap()) } -#[cfg(not(unix))] +#[cfg(any(not(unix), not(feature = "sys-poll")))] pub(crate) fn poll( - _selfs: &[&dyn VirtualFile], - _events: &[PollEventSet], - _seen_events: &mut [PollEventSet], -) -> Result<(), FsError> { - unimplemented!("VirtualFile::poll is not implemented for non-Unix-like targets yet"); + files: &[&(dyn VirtualFile + Sync)], + events: &[PollEventSet], + seen_events: &mut [PollEventSet], + timeout: Duration, +) -> Result { + if !(files.len() == events.len() && events.len() == seen_events.len()) { + tracing::debug!("the slice length of 'files', 'events' and 'seen_events' must be the same (files={}, events={}, seen_events={})", files.len(), events.len(), seen_events.len()); + return Err(FsError::InvalidInput); + } + + let mut ret = 0; + for n in 0..files.len() { + let mut builder = PollEventBuilder::new(); + + let file = files[n]; + let can_read = file + .bytes_available_read()? + .map(|_| true) + .unwrap_or(false); + let can_write = file + .bytes_available_write()? + .map(|s| s > 0) + .unwrap_or(false); + let is_closed = file.is_open() == false; + + tracing::debug!("poll_evt can_read={} can_write={} is_closed={}", can_read, can_write, is_closed); + + for event in iterate_poll_events(events[n]) { + match event { + PollEvent::PollIn if can_read => { + builder = builder.add(PollEvent::PollIn); + } + PollEvent::PollOut if can_write => { + builder = builder.add(PollEvent::PollOut); + } + PollEvent::PollHangUp if is_closed => { + builder = builder.add(PollEvent::PollHangUp); + } + PollEvent::PollInvalid if is_closed => { + builder = builder.add(PollEvent::PollInvalid); + } + PollEvent::PollError if is_closed => { + builder = builder.add(PollEvent::PollError); + } + _ => {} + } + } + let revents = builder.build(); + if revents != 0 { + ret += 1; + } + seen_events[n] = revents; + } + + if ret == 0 && timeout > Duration::ZERO { + return Err(FsError::WouldBlock); + } + + Ok(ret) } pub trait WasiPath {} diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index 1ed33a2989e..f18d9426f95 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -1,6 +1,6 @@ use crate::syscalls; use crate::syscalls::types::{self, snapshot0}; -use crate::{mem_error_to_wasi, WasiEnv}; +use crate::{mem_error_to_wasi, WasiEnv, WasiError, WasiThread}; use wasmer::WasmPtr; /// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size @@ -10,11 +10,11 @@ use wasmer::WasmPtr; /// Wasm memory. If the memory clobbered by the current syscall is also used by /// that syscall, then it may break. pub fn fd_filestat_get( - env: &WasiEnv, + thread: &WasiThread, fd: types::__wasi_fd_t, buf: WasmPtr, ) -> types::__wasi_errno_t { - let memory = env.memory(); + let memory = thread.memory(); // transmute the WasmPtr into a WasmPtr where T2 > T1, this will read extra memory. // The edge case of this cenv.mausing an OOB is not handled, if the new field is OOB, then the entire @@ -26,10 +26,10 @@ pub fn fd_filestat_get( // Set up complete, make the call with the pointer that will write to the // struct and some unrelated memory after the struct. - let result = syscalls::fd_filestat_get(env, fd, new_buf); + let result = syscalls::fd_filestat_get(thread, fd, new_buf); // reborrow memory - let memory = env.memory(); + let memory = thread.memory(); // get the values written to memory let new_filestat = wasi_try_mem!(new_buf.deref(memory).read()); @@ -59,7 +59,7 @@ pub fn fd_filestat_get( /// Wrapper around `syscalls::path_filestat_get` with extra logic to handle the size /// difference of `wasi_filestat_t` pub fn path_filestat_get( - env: &WasiEnv, + thread: &WasiThread, fd: types::__wasi_fd_t, flags: types::__wasi_lookupflags_t, path: WasmPtr, @@ -67,14 +67,14 @@ pub fn path_filestat_get( buf: WasmPtr, ) -> types::__wasi_errno_t { // see `fd_filestat_get` in this file for an explanation of this strange behavior - let memory = env.memory(); + let memory = thread.memory(); let new_buf: WasmPtr = buf.cast(); let new_filestat_setup: types::__wasi_filestat_t = wasi_try_mem!(new_buf.read(memory)); - let result = syscalls::path_filestat_get(env, fd, flags, path, path_len, new_buf); + let result = syscalls::path_filestat_get(thread, fd, flags, path, path_len, new_buf); - let memory = env.memory(); + let memory = thread.memory(); let new_filestat = wasi_try_mem!(new_buf.deref(memory).read()); let old_stat = snapshot0::__wasi_filestat_t { st_dev: new_filestat.st_dev, @@ -96,12 +96,12 @@ pub fn path_filestat_get( /// Wrapper around `syscalls::fd_seek` with extra logic to remap the values /// of `__wasi_whence_t` pub fn fd_seek( - env: &WasiEnv, + thread: &WasiThread, fd: types::__wasi_fd_t, offset: types::__wasi_filedelta_t, whence: snapshot0::__wasi_whence_t, newoffset: WasmPtr, -) -> types::__wasi_errno_t { +) -> Result { let new_whence = match whence { snapshot0::__WASI_WHENCE_CUR => types::__WASI_WHENCE_CUR, snapshot0::__WASI_WHENCE_END => types::__WASI_WHENCE_END, @@ -109,34 +109,34 @@ pub fn fd_seek( // if it's invalid, let the new fd_seek handle it _ => whence, }; - syscalls::fd_seek(env, fd, offset, new_whence, newoffset) + syscalls::fd_seek(thread, fd, offset, new_whence, newoffset) } /// Wrapper around `syscalls::poll_oneoff` with extra logic to add the removed /// userdata field back pub fn poll_oneoff( - env: &WasiEnv, + thread: &WasiThread, in_: WasmPtr, out_: WasmPtr, nsubscriptions: u32, nevents: WasmPtr, -) -> types::__wasi_errno_t { +) -> Result { // in this case the new type is smaller than the old type, so it all fits into memory, // we just need to readjust and copy it // we start by adjusting `in_` into a format that the new code can understand - let memory = env.memory(); - let in_origs = wasi_try_mem!(in_.slice(memory, nsubscriptions)); - let in_origs = wasi_try_mem!(in_origs.read_to_vec()); + let memory = thread.memory(); + let in_origs = wasi_try_mem_ok!(in_.slice(memory, nsubscriptions)); + let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); // get a pointer to the smaller new type let in_new_type_ptr: WasmPtr = in_.cast(); - for (in_sub_new, orig) in wasi_try_mem!(in_new_type_ptr.slice(memory, nsubscriptions)) + for (in_sub_new, orig) in wasi_try_mem_ok!(in_new_type_ptr.slice(memory, nsubscriptions)) .iter() .zip(in_origs.iter()) { - wasi_try_mem!(in_sub_new.write(types::__wasi_subscription_t { + wasi_try_mem_ok!(in_sub_new.write(types::__wasi_subscription_t { userdata: orig.userdata, type_: orig.type_, u: if orig.type_ == types::__WASI_EVENTTYPE_CLOCK { @@ -157,16 +157,16 @@ pub fn poll_oneoff( } // make the call - let result = syscalls::poll_oneoff(env, in_new_type_ptr, out_, nsubscriptions, nevents); + let result = syscalls::poll_oneoff(thread, in_new_type_ptr, out_, nsubscriptions, nevents); // replace the old values of in, in case the calling code reuses the memory - let memory = env.memory(); + let memory = thread.memory(); - for (in_sub, orig) in wasi_try_mem!(in_.slice(memory, nsubscriptions)) + for (in_sub, orig) in wasi_try_mem_ok!(in_.slice(memory, nsubscriptions)) .iter() .zip(in_origs.into_iter()) { - wasi_try_mem!(in_sub.write(orig)); + wasi_try_mem_ok!(in_sub.write(orig)); } result diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index fa87402614f..d2f7ded0231 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -19,6 +19,7 @@ pub mod windows; pub mod legacy; use self::types::*; +use crate::utils::map_io_err; use crate::{ mem_error_to_wasi, state::{ @@ -26,11 +27,14 @@ use crate::{ virtual_file_type_to_wasi_file_type, Fd, Inode, InodeVal, Kind, PollEvent, PollEventBuilder, WasiState, MAX_SYMLINKS, }, - WasiEnv, WasiError, + WasiEnv, WasiError, WasiThread, }; use std::borrow::Borrow; use std::convert::{Infallible, TryInto}; use std::io::{self, Read, Seek, Write}; +use std::time::Duration; +use std::ops::{Deref, DerefMut}; +use std::sync::atomic::Ordering; use tracing::{debug, trace}; use wasmer::{Memory, RuntimeError, Value, WasmPtr, WasmSlice}; use wasmer_vfs::{FsError, VirtualFile}; @@ -61,9 +65,8 @@ fn write_bytes_inner( .slice(memory, iov_inner.buf_len) .map_err(mem_error_to_wasi)?; let bytes = bytes.read_to_vec().map_err(mem_error_to_wasi)?; - write_loc.write_all(&bytes).map_err(|_| __WASI_EIO)?; + write_loc.write_all(&bytes).map_err(map_io_err)?; - // TODO: handle failure more accurately bytes_written += iov_inner.buf_len; } Ok(bytes_written) @@ -94,7 +97,7 @@ fn read_bytes( let iov_inner = iov.read().map_err(mem_error_to_wasi)?; raw_bytes.clear(); raw_bytes.resize(iov_inner.buf_len as usize, 0); - bytes_read += reader.read(&mut raw_bytes).map_err(|_| __WASI_EIO)? as u32; + bytes_read += reader.read(&mut raw_bytes).map_err(map_io_err)? as u32; let buf = WasmPtr::::new(iov_inner.buf) .slice(memory, iov_inner.buf_len) @@ -120,7 +123,7 @@ fn write_buffer_array( let mut current_buffer_offset = 0; for ((i, sub_buffer), ptr) in from.iter().enumerate().zip(ptrs.iter()) { - debug!("ptr: {:?}, subbuffer: {:?}", ptr, sub_buffer); + trace!("ptr: {:?}, subbuffer: {:?}", ptr, sub_buffer); let new_ptr = WasmPtr::new(buffer.offset() + current_buffer_offset); wasi_try_mem!(ptr.write(new_ptr)); @@ -152,12 +155,12 @@ fn get_current_time_in_nanos() -> Result<__wasi_timestamp_t, __wasi_errno_t> { /// A pointer to a buffer to write the argument string data. /// pub fn args_get( - env: &WasiEnv, + thread: &WasiThread, argv: WasmPtr>, argv_buf: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::args_get"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state) = thread.get_memory_and_wasi_state(0); let result = write_buffer_array(memory, &*state.args, argv, argv_buf); @@ -183,12 +186,12 @@ pub fn args_get( /// - `size_t *argv_buf_size` /// The size of the argument string data. pub fn args_sizes_get( - env: &WasiEnv, + thread: &WasiThread, argc: WasmPtr, argv_buf_size: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::args_sizes_get"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state) = thread.get_memory_and_wasi_state(0); let argc = argc.deref(memory); let argv_buf_size = argv_buf_size.deref(memory); @@ -212,15 +215,17 @@ pub fn args_sizes_get( /// - `__wasi_timestamp_t *resolution` /// The resolution of the clock in nanoseconds pub fn clock_res_get( - env: &WasiEnv, + thread: &WasiThread, clock_id: __wasi_clockid_t, resolution: WasmPtr<__wasi_timestamp_t>, ) -> __wasi_errno_t { - debug!("wasi::clock_res_get"); - let memory = env.memory(); + trace!("wasi::clock_res_get"); + let memory = thread.memory(); let out_addr = resolution.deref(memory); - platform_clock_res_get(clock_id, out_addr) + let t_out = wasi_try!(platform_clock_res_get(clock_id, out_addr)); + wasi_try_mem!(resolution.write(memory, t_out as __wasi_timestamp_t)); + __WASI_ESUCCESS } /// ### `clock_time_get()` @@ -234,20 +239,24 @@ pub fn clock_res_get( /// - `__wasi_timestamp_t *time` /// The value of the clock in nanoseconds pub fn clock_time_get( - env: &WasiEnv, + thread: &WasiThread, clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, time: WasmPtr<__wasi_timestamp_t>, ) -> __wasi_errno_t { debug!( "wasi::clock_time_get clock_id: {}, precision: {}", - clock_id, precision + clock_id, + precision ); - let memory = env.memory(); + let memory = thread.memory(); let out_addr = time.deref(memory); - let result = platform_clock_time_get(clock_id, precision, out_addr); - debug!( + let t_out = wasi_try!(platform_clock_time_get(clock_id, precision)); + wasi_try_mem!(time.write(memory, t_out as __wasi_timestamp_t)); + + let result = __WASI_ESUCCESS; + trace!( "time: {} => {}", wasi_try_mem!(time.deref(memory).read()), result @@ -264,7 +273,7 @@ pub fn clock_time_get( /// - `char *environ_buf` /// A pointer to a buffer to write the environment variable string data. pub fn environ_get( - env: &WasiEnv, + thread: &WasiThread, environ: WasmPtr>, environ_buf: WasmPtr, ) -> __wasi_errno_t { @@ -272,8 +281,8 @@ pub fn environ_get( "wasi::environ_get. Environ: {:?}, environ_buf: {:?}", environ, environ_buf ); - let (memory, mut state) = env.get_memory_and_wasi_state(0); - debug!(" -> State envs: {:?}", state.envs); + let (memory, state) = thread.get_memory_and_wasi_state(0); + trace!(" -> State envs: {:?}", state.envs); write_buffer_array(memory, &*state.envs, environ, environ_buf) } @@ -286,12 +295,12 @@ pub fn environ_get( /// - `size_t *environ_buf_size` /// The size of the environment variable string data. pub fn environ_sizes_get( - env: &WasiEnv, + thread: &WasiThread, environ_count: WasmPtr, environ_buf_size: WasmPtr, ) -> __wasi_errno_t { - debug!("wasi::environ_sizes_get"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + trace!("wasi::environ_sizes_get"); + let (memory, state) = thread.get_memory_and_wasi_state(0); let environ_count = environ_count.deref(memory); let environ_buf_size = environ_buf_size.deref(memory); @@ -301,9 +310,10 @@ pub fn environ_sizes_get( wasi_try_mem!(environ_count.write(env_var_count)); wasi_try_mem!(environ_buf_size.write(env_buf_size)); - debug!( + trace!( "env_var_count: {}, env_buf_size: {}", - env_var_count, env_buf_size + env_var_count, + env_buf_size ); __WASI_ESUCCESS @@ -321,7 +331,7 @@ pub fn environ_sizes_get( /// - `__wasi_advice_t advice` /// The advice to give pub fn fd_advise( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, @@ -344,36 +354,38 @@ pub fn fd_advise( /// - `__wasi_filesize_t len` /// The length from the offset marking the end of the allocation pub fn fd_allocate( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, ) -> __wasi_errno_t { debug!("wasi::fd_allocate"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_ALLOCATE) { return __WASI_EACCES; } - let new_size = wasi_try!(offset.checked_add(len), __WASI_EINVAL); - - match &mut state.fs.inodes[inode].kind { - Kind::File { handle, .. } => { - if let Some(handle) = handle { - wasi_try!(handle.set_len(new_size).map_err(fs_error_into_wasi_err)); - } else { - return __WASI_EBADF; + let new_size = wasi_try!(offset.checked_add(len).ok_or(__WASI_EINVAL)); + { + let mut guard = inodes.arena[inode].write(); + match guard.deref_mut() { + Kind::File { handle, .. } => { + if let Some(handle) = handle { + wasi_try!(handle.set_len(new_size).map_err(fs_error_into_wasi_err)); + } else { + return __WASI_EBADF; + } } + Kind::Buffer { buffer } => { + buffer.resize(new_size as usize, 0); + } + Kind::Symlink { .. } => return __WASI_EBADF, + Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, } - Kind::Buffer { buffer } => { - buffer.resize(new_size as usize, 0); - } - Kind::Symlink { .. } => return __WASI_EBADF, - Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, } - state.fs.inodes[inode].stat.st_size = new_size; + inodes.arena[inode].stat.write().unwrap().st_size = new_size; debug!("New file size: {}", new_size); __WASI_ESUCCESS @@ -389,13 +401,13 @@ pub fn fd_allocate( /// If `fd` is a directory /// - `__WASI_EBADF` /// If `fd` is invalid or not open -pub fn fd_close(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { +pub fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_close: fd={}", fd); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); - wasi_try!(state.fs.close_fd(fd)); + wasi_try!(state.fs.close_fd(inodes.deref(), fd)); __WASI_ESUCCESS } @@ -405,15 +417,15 @@ pub fn fd_close(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { /// Inputs: /// - `__wasi_fd_t fd` /// The file descriptor to sync -pub fn fd_datasync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { +pub fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_datasync"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_DATASYNC) { return __WASI_EACCES; } - if let Err(e) = state.fs.flush(fd) { + if let Err(e) = state.fs.flush(inodes.deref(), fd) { e } else { __WASI_ESUCCESS @@ -429,7 +441,7 @@ pub fn fd_datasync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { /// - `__wasi_fdstat_t *buf` /// The location where the metadata will be written pub fn fd_fdstat_get( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, buf_ptr: WasmPtr<__wasi_fdstat_t>, ) -> __wasi_errno_t { @@ -438,10 +450,8 @@ pub fn fd_fdstat_get( fd, buf_ptr.offset() ); - let (memory, mut state) = env.get_memory_and_wasi_state(0); - let fd_entry = wasi_try!(state.fs.get_fd(fd)); - - let stat = wasi_try!(state.fs.fdstat(fd)); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let stat = wasi_try!(state.fs.fdstat(inodes.deref(), fd)); let buf = buf_ptr.deref(memory); wasi_try_mem!(buf.write(stat)); @@ -457,13 +467,14 @@ pub fn fd_fdstat_get( /// - `__wasi_fdflags_t flags` /// The flags to apply to `fd` pub fn fd_fdstat_set_flags( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, flags: __wasi_fdflags_t, ) -> __wasi_errno_t { debug!("wasi::fd_fdstat_set_flags"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + let (memory, state) = thread.get_memory_and_wasi_state(0); + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_FDSTAT_SET_FLAGS) { return __WASI_EACCES; @@ -483,14 +494,15 @@ pub fn fd_fdstat_set_flags( /// - `__wasi_rights_t fs_rights_inheriting` /// The inheriting rights to apply to `fd` pub fn fd_fdstat_set_rights( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, fs_rights_base: __wasi_rights_t, fs_rights_inheriting: __wasi_rights_t, ) -> __wasi_errno_t { debug!("wasi::fd_fdstat_set_rights"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + let (memory, state) = thread.get_memory_and_wasi_state(0); + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); // ensure new rights are a subset of current rights if fd_entry.rights | fs_rights_base != fd_entry.rights @@ -514,18 +526,18 @@ pub fn fd_fdstat_set_rights( /// - `__wasi_filestat_t *buf` /// Where the metadata from `fd` will be written pub fn fd_filestat_get( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, buf: WasmPtr<__wasi_filestat_t>, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_get"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_FILESTAT_GET) { return __WASI_EACCES; } - let stat = wasi_try!(state.fs.filestat_fd(fd)); + let stat = wasi_try!(state.fs.filestat_fd(inodes.deref(), fd)); let buf = buf.deref(memory); wasi_try_mem!(buf.write(stat)); @@ -541,12 +553,12 @@ pub fn fd_filestat_get( /// - `__wasi_filesize_t st_size` /// New size that `fd` will be set to pub fn fd_filestat_set_size( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, st_size: __wasi_filesize_t, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_set_size"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; @@ -554,21 +566,24 @@ pub fn fd_filestat_set_size( return __WASI_EACCES; } - match &mut state.fs.inodes[inode].kind { - Kind::File { handle, .. } => { - if let Some(handle) = handle { - wasi_try!(handle.set_len(st_size).map_err(fs_error_into_wasi_err)); - } else { - return __WASI_EBADF; + { + let mut guard = inodes.arena[inode].write(); + match guard.deref_mut() { + Kind::File { handle, .. } => { + if let Some(handle) = handle { + wasi_try!(handle.set_len(st_size).map_err(fs_error_into_wasi_err)); + } else { + return __WASI_EBADF; + } } + Kind::Buffer { buffer } => { + buffer.resize(st_size as usize, 0); + } + Kind::Symlink { .. } => return __WASI_EBADF, + Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, } - Kind::Buffer { buffer } => { - buffer.resize(st_size as usize, 0); - } - Kind::Symlink { .. } => return __WASI_EBADF, - Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, } - state.fs.inodes[inode].stat.st_size = st_size; + inodes.arena[inode].stat.write().unwrap().st_size = st_size; __WASI_ESUCCESS } @@ -583,15 +598,15 @@ pub fn fd_filestat_set_size( /// - `__wasi_fstflags_t fst_flags` /// Bit-vector for controlling which times get set pub fn fd_filestat_set_times( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, st_atim: __wasi_timestamp_t, st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_set_times"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_FILESTAT_SET_TIMES) { return __WASI_EACCES; @@ -605,7 +620,7 @@ pub fn fd_filestat_set_times( } let inode_idx = fd_entry.inode; - let inode = &mut state.fs.inodes[inode_idx]; + let inode = &inodes.arena[inode_idx]; if fst_flags & __WASI_FILESTAT_SET_ATIM != 0 || fst_flags & __WASI_FILESTAT_SET_ATIM_NOW != 0 { let time_to_set = if fst_flags & __WASI_FILESTAT_SET_ATIM != 0 { @@ -613,7 +628,7 @@ pub fn fd_filestat_set_times( } else { wasi_try!(get_current_time_in_nanos()) }; - inode.stat.st_atim = time_to_set; + inode.stat.write().unwrap().st_atim = time_to_set; } if fst_flags & __WASI_FILESTAT_SET_MTIM != 0 || fst_flags & __WASI_FILESTAT_SET_MTIM_NOW != 0 { @@ -622,7 +637,7 @@ pub fn fd_filestat_set_times( } else { wasi_try!(get_current_time_in_nanos()) }; - inode.stat.st_mtim = time_to_set; + inode.stat.write().unwrap().st_mtim = time_to_set; } __WASI_ESUCCESS @@ -644,33 +659,37 @@ pub fn fd_filestat_set_times( /// - `size_t nread` /// The number of bytes read pub fn fd_pread( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t>, iovs_len: u32, offset: __wasi_filesize_t, nread: WasmPtr, -) -> __wasi_errno_t { - debug!("wasi::fd_pread: fd={}, offset={}", fd, offset); - let (memory, mut state) = env.get_memory_and_wasi_state(0); +) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::fd_pread: fd={}, offset={}", fd, offset); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); - let iovs = wasi_try_mem!(iovs.slice(memory, iovs_len)); + let iovs = wasi_try_mem_ok!(iovs.slice(memory, iovs_len)); let nread_ref = nread.deref(memory); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let bytes_read = match fd { __WASI_STDIN_FILENO => { - if let Some(ref mut stdin) = - wasi_try!(state.fs.stdin_mut().map_err(fs_error_into_wasi_err)) - { - wasi_try!(read_bytes(stdin, memory, iovs)) + let mut guard = wasi_try_ok!( + inodes + .stdin_mut(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ); + if let Some(ref mut stdin) = guard.deref_mut() { + wasi_try_ok!(read_bytes(stdin, memory, iovs), thread) } else { - return __WASI_EBADF; + return Ok(__WASI_EBADF); } } - __WASI_STDOUT_FILENO => return __WASI_EINVAL, - __WASI_STDERR_FILENO => return __WASI_EINVAL, + __WASI_STDOUT_FILENO => return Ok(__WASI_EINVAL), + __WASI_STDERR_FILENO => return Ok(__WASI_EINVAL), _ => { - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); let inode = fd_entry.inode; if !(has_rights(fd_entry.rights, __WASI_RIGHT_FD_READ) @@ -680,32 +699,37 @@ pub fn fd_pread( "Invalid rights on {:X}: expected READ and SEEK", fd_entry.rights ); - return __WASI_EACCES; + return Ok(__WASI_EACCES); } - match &mut state.fs.inodes[inode].kind { + let mut guard = inodes.arena[inode].write(); + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(h) = handle { - wasi_try!( - h.seek(std::io::SeekFrom::Start(offset as u64)).ok(), - __WASI_EIO + wasi_try_ok!( + h.seek(std::io::SeekFrom::Start(offset as u64)) + .map_err(map_io_err), + thread ); - wasi_try!(read_bytes(h, memory, iovs)) + wasi_try_ok!(read_bytes(h, memory, iovs), thread) } else { - return __WASI_EINVAL; + return Ok(__WASI_EINVAL); } } - Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, + Kind::Dir { .. } | Kind::Root { .. } => return Ok(__WASI_EISDIR), Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"), Kind::Buffer { buffer } => { - wasi_try!(read_bytes(&buffer[(offset as usize)..], memory, iovs)) + wasi_try_ok!( + read_bytes(&buffer[(offset as usize)..], memory, iovs), + thread + ) } } } }; - wasi_try_mem!(nread_ref.write(bytes_read)); + wasi_try_mem_ok!(nread_ref.write(bytes_read)); debug!("Success: {} bytes read", bytes_read); - __WASI_ESUCCESS + Ok(__WASI_ESUCCESS) } /// ### `fd_prestat_get()` @@ -717,40 +741,42 @@ pub fn fd_pread( /// - `__wasi_prestat *buf` /// Where the metadata will be written pub fn fd_prestat_get( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, buf: WasmPtr<__wasi_prestat_t>, ) -> __wasi_errno_t { - debug!("wasi::fd_prestat_get: fd={}", fd); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + trace!("wasi::fd_prestat_get: fd={}", fd); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let prestat_ptr = buf.deref(memory); - wasi_try_mem!(prestat_ptr.write(wasi_try!(state.fs.prestat_fd(fd)))); + wasi_try_mem!(prestat_ptr.write(wasi_try!(state.fs.prestat_fd(inodes.deref(), fd)))); __WASI_ESUCCESS } pub fn fd_prestat_dir_name( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, path: WasmPtr, path_len: u32, ) -> __wasi_errno_t { - debug!( + trace!( "wasi::fd_prestat_dir_name: fd={}, path_len={}", - fd, path_len + fd, + path_len ); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let path_chars = wasi_try_mem!(path.slice(memory, path_len)); - let real_fd = wasi_try!(state.fs.fd_map.get(&fd).ok_or(__WASI_EBADF)); - let inode_val = &state.fs.inodes[real_fd.inode]; + let real_inode = wasi_try!(state.fs.get_fd_inode(fd)); + let inode_val = &inodes.arena[real_inode]; // check inode-val.is_preopened? - debug!("=> inode: {:?}", inode_val); - match inode_val.kind { + trace!("=> inode: {:?}", inode_val); + let guard = inode_val.read(); + match guard.deref() { Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify this: null termination, etc if inode_val.name.len() < path_len as usize { @@ -759,7 +785,7 @@ pub fn fd_prestat_dir_name( .write_slice(inode_val.name.as_bytes())); wasi_try_mem!(path_chars.index(inode_val.name.len() as u64).write(0)); - debug!("=> result: \"{}\"", inode_val.name); + trace!("=> result: \"{}\"", inode_val.name); __WASI_ESUCCESS } else { @@ -785,79 +811,91 @@ pub fn fd_prestat_dir_name( /// - `u32 *nwritten` /// Number of bytes written pub fn fd_pwrite( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t>, iovs_len: u32, offset: __wasi_filesize_t, nwritten: WasmPtr, -) -> __wasi_errno_t { - debug!("wasi::fd_pwrite"); +) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::fd_pwrite"); // TODO: refactor, this is just copied from `fd_write`... - let (memory, mut state) = env.get_memory_and_wasi_state(0); - let iovs_arr = wasi_try_mem!(iovs.slice(memory, iovs_len)); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let iovs_arr = wasi_try_mem_ok!(iovs.slice(memory, iovs_len)); let nwritten_ref = nwritten.deref(memory); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let bytes_written = match fd { - __WASI_STDIN_FILENO => return __WASI_EINVAL, + __WASI_STDIN_FILENO => return Ok(__WASI_EINVAL), __WASI_STDOUT_FILENO => { - if let Some(ref mut stdout) = - wasi_try!(state.fs.stdout_mut().map_err(fs_error_into_wasi_err)) - { - wasi_try!(write_bytes(stdout, memory, iovs_arr)) + let mut guard = wasi_try_ok!( + inodes + .stdout_mut(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ); + if let Some(ref mut stdout) = guard.deref_mut() { + wasi_try_ok!(write_bytes(stdout, memory, iovs_arr), thread) } else { - return __WASI_EBADF; + return Ok(__WASI_EBADF); } } __WASI_STDERR_FILENO => { - if let Some(ref mut stderr) = - wasi_try!(state.fs.stderr_mut().map_err(fs_error_into_wasi_err)) - { - wasi_try!(write_bytes(stderr, memory, iovs_arr)) + let mut guard = wasi_try_ok!( + inodes + .stderr_mut(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ); + if let Some(ref mut stderr) = guard.deref_mut() { + wasi_try_ok!(write_bytes(stderr, memory, iovs_arr), thread) } else { - return __WASI_EBADF; + return Ok(__WASI_EBADF); } } _ => { - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); - if !(has_rights(fd_entry.rights, __WASI_RIGHT_FD_WRITE) && has_rights(fd_entry.rights, __WASI_RIGHT_FD_SEEK)) { - return __WASI_EACCES; + return Ok(__WASI_EACCES); } let inode_idx = fd_entry.inode; - let inode = &mut state.fs.inodes[inode_idx]; + let inode = &inodes.arena[inode_idx]; - match &mut inode.kind { + let mut guard = inode.write(); + match guard.deref_mut() { Kind::File { handle, .. } => { if let Some(handle) = handle { - handle.seek(std::io::SeekFrom::Start(offset as u64)); - wasi_try!(write_bytes(handle, memory, iovs_arr)) + wasi_try_ok!( + handle + .seek(std::io::SeekFrom::Start(offset as u64)) + .map_err(map_io_err), + thread + ); + wasi_try_ok!(write_bytes(handle, memory, iovs_arr), thread) } else { - return __WASI_EINVAL; + return Ok(__WASI_EINVAL); } } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify - return __WASI_EISDIR; + return Ok(__WASI_EISDIR); } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pwrite"), Kind::Buffer { buffer } => { - wasi_try!(write_bytes( - &mut buffer[(offset as usize)..], - memory, - iovs_arr - )) + wasi_try_ok!( + write_bytes(&mut buffer[(offset as usize)..], memory, iovs_arr), + thread + ) } } } }; - wasi_try_mem!(nwritten_ref.write(bytes_written)); + wasi_try_mem_ok!(nwritten_ref.write(bytes_written)); - __WASI_ESUCCESS + Ok(__WASI_ESUCCESS) } /// ### `fd_read()` @@ -873,71 +911,83 @@ pub fn fd_pwrite( /// - `u32 *nread` /// Number of bytes read pub fn fd_read( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t>, iovs_len: u32, nread: WasmPtr, -) -> __wasi_errno_t { - debug!("wasi::fd_read: fd={}", fd); - let (memory, mut state) = env.get_memory_and_wasi_state(0); +) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::fd_read: fd={}", fd); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); - let iovs_arr = wasi_try_mem!(iovs.slice(memory, iovs_len)); + let iovs_arr = wasi_try_mem_ok!(iovs.slice(memory, iovs_len)); let nread_ref = nread.deref(memory); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let bytes_read = match fd { __WASI_STDIN_FILENO => { - if let Some(ref mut stdin) = - wasi_try!(state.fs.stdin_mut().map_err(fs_error_into_wasi_err)) - { - wasi_try!(read_bytes(stdin, memory, iovs_arr)) + let mut guard = wasi_try_ok!( + inodes + .stdin_mut(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ); + if let Some(ref mut stdin) = guard.deref_mut() { + wasi_try_ok!(read_bytes(stdin, memory, iovs_arr), thread) } else { - return __WASI_EBADF; + return Ok(__WASI_EBADF); } } - __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => return __WASI_EINVAL, + __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => return Ok(__WASI_EINVAL), _ => { - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); - if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_READ) { // TODO: figure out the error to return when lacking rights - return __WASI_EACCES; + return Ok(__WASI_EACCES); } let offset = fd_entry.offset as usize; let inode_idx = fd_entry.inode; - let inode = &mut state.fs.inodes[inode_idx]; - - let bytes_read = match &mut inode.kind { - Kind::File { handle, .. } => { - if let Some(handle) = handle { - handle.seek(std::io::SeekFrom::Start(offset as u64)); - wasi_try!(read_bytes(handle, memory, iovs_arr)) - } else { - return __WASI_EINVAL; + let inode = &inodes.arena[inode_idx]; + + let bytes_read = { + let mut guard = inode.write(); + match guard.deref_mut() { + Kind::File { handle, .. } => { + if let Some(handle) = handle { + wasi_try_ok!( + handle + .seek(std::io::SeekFrom::Start(offset as u64)) + .map_err(map_io_err), + thread + ); + wasi_try_ok!(read_bytes(handle, memory, iovs_arr), thread) + } else { + return Ok(__WASI_EINVAL); + } + } + Kind::Dir { .. } | Kind::Root { .. } => { + // TODO: verify + return Ok(__WASI_EISDIR); + } + Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"), + Kind::Buffer { buffer } => { + wasi_try_ok!(read_bytes(&buffer[offset..], memory, iovs_arr), thread) } - } - Kind::Dir { .. } | Kind::Root { .. } => { - // TODO: verify - return __WASI_EISDIR; - } - Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"), - Kind::Buffer { buffer } => { - wasi_try!(read_bytes(&buffer[offset..], memory, iovs_arr)) } }; // reborrow - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); fd_entry.offset += bytes_read as u64; bytes_read } }; - wasi_try_mem!(nread_ref.write(bytes_read)); + wasi_try_mem_ok!(nread_ref.write(bytes_read)); - __WASI_ESUCCESS + Ok(__WASI_ESUCCESS) } /// ### `fd_readdir()` @@ -956,84 +1006,83 @@ pub fn fd_read( /// The Number of bytes stored in `buf`; if less than `buf_len` then entire /// directory has been read pub fn fd_readdir( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, buf: WasmPtr, buf_len: u32, cookie: __wasi_dircookie_t, bufused: WasmPtr, ) -> __wasi_errno_t { - debug!("wasi::fd_readdir"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + trace!("wasi::fd_readdir"); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); // TODO: figure out how this is supposed to work; // is it supposed to pack the buffer full every time until it can't? or do one at a time? let buf_arr = wasi_try_mem!(buf.slice(memory, buf_len)); let bufused_ref = bufused.deref(memory); - let working_dir = wasi_try!(state.fs.fd_map.get(&fd).ok_or(__WASI_EBADF)); + let working_dir = wasi_try!(state.fs.get_fd(fd)); let mut cur_cookie = cookie; let mut buf_idx = 0; - let entries: Vec<(String, u8, u64)> = match &state.fs.inodes[working_dir.inode].kind { - Kind::Dir { path, entries, .. } => { - debug!("Reading dir {:?}", path); - // TODO: refactor this code - // we need to support multiple calls, - // simple and obviously correct implementation for now: - // maintain consistent order via lexacographic sorting - let fs_info = wasi_try!(wasi_try!(state.fs_read_dir(path)) - .collect::, _>>() - .map_err(|_| __WASI_EIO)); - let mut entry_vec = wasi_try!(fs_info - .into_iter() - .map(|entry| { - let filename = entry.file_name().to_string_lossy().to_string(); - debug!("Getting file: {:?}", filename); - let filetype = virtual_file_type_to_wasi_file_type( - entry.file_type().map_err(|_| __WASI_EIO)?, - ); - Ok(( - filename, filetype, 0, // TODO: inode - )) - }) - .collect::, _>>()); - entry_vec.extend( - entries - .iter() - .filter(|(_, inode)| state.fs.inodes[**inode].is_preopened) - .map(|(name, inode)| { - let entry = &state.fs.inodes[*inode]; - ( - entry.name.to_string(), - entry.stat.st_filetype, - entry.stat.st_ino, - ) - }), - ); - entry_vec.sort_by(|a, b| a.0.cmp(&b.0)); - entry_vec - } - Kind::Root { entries } => { - debug!("Reading root"); - let sorted_entries = { - let mut entry_vec: Vec<(String, Inode)> = - entries.iter().map(|(a, b)| (a.clone(), *b)).collect(); + let entries: Vec<(String, u8, u64)> = { + let guard = inodes.arena[working_dir.inode].read(); + match guard.deref() { + Kind::Dir { path, entries, .. } => { + debug!("Reading dir {:?}", path); + // TODO: refactor this code + // we need to support multiple calls, + // simple and obviously correct implementation for now: + // maintain consistent order via lexacographic sorting + let fs_info = wasi_try!(wasi_try!(state.fs_read_dir(path)) + .collect::, _>>() + .map_err(|e| fs_error_into_wasi_err(e))); + let mut entry_vec = wasi_try!(fs_info + .into_iter() + .map(|entry| { + let filename = entry.file_name().to_string_lossy().to_string(); + debug!("Getting file: {:?}", filename); + let filetype = virtual_file_type_to_wasi_file_type( + entry.file_type().map_err(fs_error_into_wasi_err)?, + ); + Ok(( + filename, filetype, 0, // TODO: inode + )) + }) + .collect::, _>>()); + entry_vec.extend( + entries + .iter() + .filter(|(_, inode)| inodes.arena[**inode].is_preopened) + .map(|(name, inode)| { + let entry = &inodes.arena[*inode]; + let stat = entry.stat.read().unwrap(); + (entry.name.to_string(), stat.st_filetype, stat.st_ino) + }), + ); entry_vec.sort_by(|a, b| a.0.cmp(&b.0)); entry_vec - }; - sorted_entries - .into_iter() - .map(|(name, inode)| { - let entry = &state.fs.inodes[inode]; - ( - format!("/{}", entry.name), - entry.stat.st_filetype, - entry.stat.st_ino, - ) - }) - .collect() + } + Kind::Root { entries } => { + debug!("Reading root"); + let sorted_entries = { + let mut entry_vec: Vec<(String, Inode)> = + entries.iter().map(|(a, b)| (a.clone(), *b)).collect(); + entry_vec.sort_by(|a, b| a.0.cmp(&b.0)); + entry_vec + }; + sorted_entries + .into_iter() + .map(|(name, inode)| { + let entry = &inodes.arena[inode]; + let stat = entry.stat.read().unwrap(); + (format!("/{}", entry.name), stat.st_filetype, stat.st_ino) + }) + .collect() + } + Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => { + return __WASI_ENOTDIR + } } - Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => return __WASI_ENOTDIR, }; for (entry_path_str, wasi_file_type, ino) in entries.iter().skip(cookie as usize) { @@ -1079,18 +1128,21 @@ pub fn fd_readdir( /// File descriptor to copy /// - `__wasi_fd_t to` /// Location to copy file descriptor to -pub fn fd_renumber(env: &WasiEnv, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { +pub fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_renumber: from={}, to={}", from, to); - let (memory, mut state) = env.get_memory_and_wasi_state(0); - let fd_entry = wasi_try!(state.fs.fd_map.get(&from).ok_or(__WASI_EBADF)); + let (memory, state) = thread.get_memory_and_wasi_state(0); + + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try!(fd_map.get_mut(&from).ok_or(__WASI_EBADF)); + let new_fd_entry = Fd { // TODO: verify this is correct rights: fd_entry.rights_inheriting, ..*fd_entry }; - state.fs.fd_map.insert(to, new_fd_entry); - state.fs.fd_map.remove(&from); + fd_map.insert(to, new_fd_entry); + fd_map.remove(&from); __WASI_ESUCCESS } @@ -1107,39 +1159,45 @@ pub fn fd_renumber(env: &WasiEnv, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_ /// - `__wasi_filesize_t *fd` /// The new offset relative to the start of the file pub fn fd_seek( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, offset: __wasi_filedelta_t, whence: __wasi_whence_t, newoffset: WasmPtr<__wasi_filesize_t>, -) -> __wasi_errno_t { - debug!("wasi::fd_seek: fd={}, offset={}", fd, offset); - let (memory, mut state) = env.get_memory_and_wasi_state(0); +) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::fd_seek: fd={}, offset={}", fd, offset); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let new_offset_ref = newoffset.deref(memory); - - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_SEEK) { - return __WASI_EACCES; + return Ok(__WASI_EACCES); } // TODO: handle case if fd is a dir? match whence { - __WASI_WHENCE_CUR => fd_entry.offset = (fd_entry.offset as i64 + offset) as u64, + __WASI_WHENCE_CUR => { + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + fd_entry.offset = (fd_entry.offset as i64 + offset) as u64 + } __WASI_WHENCE_END => { use std::io::SeekFrom; let inode_idx = fd_entry.inode; - match state.fs.inodes[inode_idx].kind { + let mut guard = inodes.arena[inode_idx].write(); + match guard.deref_mut() { Kind::File { ref mut handle, .. } => { if let Some(handle) = handle { - let end = wasi_try!(handle.seek(SeekFrom::End(0)).ok().ok_or(__WASI_EIO)); - // TODO: handle case if fd_entry.offset uses 64 bits of a u64 + let end = + wasi_try_ok!(handle.seek(SeekFrom::End(0)).map_err(map_io_err), thread); - // reborrow - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + // TODO: handle case if fd_entry.offset uses 64 bits of a u64 + drop(guard); + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); fd_entry.offset = (end as i64 + offset) as u64; } else { - return __WASI_EINVAL; + return Ok(__WASI_EINVAL); } } Kind::Symlink { .. } => { @@ -1147,23 +1205,27 @@ pub fn fd_seek( } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: check this - return __WASI_EINVAL; + return Ok(__WASI_EINVAL); } Kind::Buffer { .. } => { // seeking buffers probably makes sense // TODO: implement this - return __WASI_EINVAL; + return Ok(__WASI_EINVAL); } } } - __WASI_WHENCE_SET => fd_entry.offset = offset as u64, - _ => return __WASI_EINVAL, + __WASI_WHENCE_SET => { + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + fd_entry.offset = offset as u64 + } + _ => return Ok(__WASI_EINVAL), } // reborrow - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); - wasi_try_mem!(new_offset_ref.write(fd_entry.offset)); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); + wasi_try_mem_ok!(new_offset_ref.write(fd_entry.offset)); - __WASI_ESUCCESS + Ok(__WASI_ESUCCESS) } /// ### `fd_sync()` @@ -1175,10 +1237,10 @@ pub fn fd_seek( /// TODO: figure out which errors this should return /// - `__WASI_EPERM` /// - `__WASI_ENOTCAPABLE` -pub fn fd_sync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { +pub fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_sync"); debug!("=> fd={}", fd); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_SYNC) { return __WASI_EACCES; @@ -1186,16 +1248,19 @@ pub fn fd_sync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { let inode = fd_entry.inode; // TODO: implement this for more than files - match &mut state.fs.inodes[inode].kind { - Kind::File { handle, .. } => { - if let Some(h) = handle { - wasi_try!(h.sync_to_disk().map_err(fs_error_into_wasi_err)); - } else { - return __WASI_EINVAL; + { + let mut guard = inodes.arena[inode].write(); + match guard.deref_mut() { + Kind::File { handle, .. } => { + if let Some(h) = handle { + wasi_try!(h.sync_to_disk().map_err(fs_error_into_wasi_err)); + } else { + return __WASI_EINVAL; + } } + Kind::Root { .. } | Kind::Dir { .. } => return __WASI_EISDIR, + Kind::Buffer { .. } | Kind::Symlink { .. } => return __WASI_EINVAL, } - Kind::Root { .. } | Kind::Dir { .. } => return __WASI_EISDIR, - Kind::Buffer { .. } | Kind::Symlink { .. } => return __WASI_EINVAL, } __WASI_ESUCCESS @@ -1210,15 +1275,15 @@ pub fn fd_sync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { /// - `__wasi_filesize_t *offset` /// The offset of `fd` relative to the start of the file pub fn fd_tell( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, offset: WasmPtr<__wasi_filesize_t>, ) -> __wasi_errno_t { debug!("wasi::fd_tell"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state) = thread.get_memory_and_wasi_state(0); let offset_ref = offset.deref(memory); - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_TELL) { return __WASI_EACCES; @@ -1244,86 +1309,97 @@ pub fn fd_tell( /// Errors: /// pub fn fd_write( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t>, iovs_len: u32, nwritten: WasmPtr, -) -> __wasi_errno_t { - // If we are writing to stdout or stderr - // we skip debug to not pollute the stdout/err - // and do debugging happily after :) - if fd != __WASI_STDOUT_FILENO && fd != __WASI_STDERR_FILENO { - debug!("wasi::fd_write: fd={}", fd); - } else { - trace!("wasi::fd_write: fd={}", fd); - } - let (memory, mut state) = env.get_memory_and_wasi_state(0); - let iovs_arr = wasi_try_mem!(iovs.slice(memory, iovs_len)); +) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::fd_write: fd={}", fd); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let iovs_arr = wasi_try_mem_ok!(iovs.slice(memory, iovs_len)); let nwritten_ref = nwritten.deref(memory); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); let bytes_written = match fd { - __WASI_STDIN_FILENO => return __WASI_EINVAL, + __WASI_STDIN_FILENO => return Ok(__WASI_EINVAL), __WASI_STDOUT_FILENO => { - if let Some(ref mut stdout) = - wasi_try!(state.fs.stdout_mut().map_err(fs_error_into_wasi_err)) - { - wasi_try!(write_bytes(stdout, memory, iovs_arr)) + let mut guard = wasi_try_ok!( + inodes + .stdout_mut(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ); + if let Some(ref mut stdout) = guard.deref_mut() { + wasi_try_ok!(write_bytes(stdout, memory, iovs_arr), thread) } else { - return __WASI_EBADF; + return Ok(__WASI_EBADF); } } __WASI_STDERR_FILENO => { - if let Some(ref mut stderr) = - wasi_try!(state.fs.stderr_mut().map_err(fs_error_into_wasi_err)) - { - wasi_try!(write_bytes(stderr, memory, iovs_arr)) + let mut guard = wasi_try_ok!( + inodes + .stderr_mut(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ); + if let Some(ref mut stderr) = guard.deref_mut() { + wasi_try_ok!(write_bytes(stderr, memory, iovs_arr), thread) } else { - return __WASI_EBADF; + return Ok(__WASI_EBADF); } } _ => { - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); - if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_WRITE) { - return __WASI_EACCES; + return Ok(__WASI_EACCES); } let offset = fd_entry.offset as usize; let inode_idx = fd_entry.inode; - let inode = &mut state.fs.inodes[inode_idx]; - - let bytes_written = match &mut inode.kind { - Kind::File { handle, .. } => { - if let Some(handle) = handle { - handle.seek(std::io::SeekFrom::Start(offset as u64)); - wasi_try!(write_bytes(handle, memory, iovs_arr)) - } else { - return __WASI_EINVAL; + let inode = &inodes.arena[inode_idx]; + + let bytes_written = { + let mut guard = inode.write(); + match guard.deref_mut() { + Kind::File { handle, .. } => { + if let Some(handle) = handle { + wasi_try_ok!( + handle + .seek(std::io::SeekFrom::Start(offset as u64)) + .map_err(map_io_err), + thread + ); + wasi_try_ok!(write_bytes(handle, memory, iovs_arr), thread) + } else { + return Ok(__WASI_EINVAL); + } + } + Kind::Dir { .. } | Kind::Root { .. } => { + // TODO: verify + return Ok(__WASI_EISDIR); + } + Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"), + Kind::Buffer { buffer } => { + wasi_try_ok!(write_bytes(&mut buffer[offset..], memory, iovs_arr), thread) } - } - Kind::Dir { .. } | Kind::Root { .. } => { - // TODO: verify - return __WASI_EISDIR; - } - Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"), - Kind::Buffer { buffer } => { - wasi_try!(write_bytes(&mut buffer[offset..], memory, iovs_arr)) } }; // reborrow - let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); - fd_entry.offset += bytes_written as u64; - wasi_try!(state.fs.filestat_resync_size(fd)); + { + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); + fd_entry.offset += bytes_written as u64; + } + wasi_try_ok!(state.fs.filestat_resync_size(inodes.deref(), fd), thread); bytes_written } }; - wasi_try_mem!(nwritten_ref.write(bytes_written)); + wasi_try_mem_ok!(nwritten_ref.write(bytes_written)); - __WASI_ESUCCESS + Ok(__WASI_ESUCCESS) } /// ### `path_create_directory()` @@ -1340,17 +1416,20 @@ pub fn fd_write( /// - __WASI_RIGHT_PATH_CREATE_DIRECTORY /// This right must be set on the directory that the file is created in (TODO: verify that this is true) pub fn path_create_directory( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, path: WasmPtr, path_len: u32, ) -> __wasi_errno_t { debug!("wasi::path_create_directory"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); let working_dir = wasi_try!(state.fs.get_fd(fd)); - if let Kind::Root { .. } = &state.fs.inodes[working_dir.inode].kind { - return __WASI_EACCES; + { + let guard = inodes.arena[working_dir.inode].read(); + if let Kind::Root { .. } = guard.deref() { + return __WASI_EACCES; + } } if !has_rights(working_dir.rights, __WASI_RIGHT_PATH_CREATE_DIRECTORY) { return __WASI_EACCES; @@ -1377,7 +1456,8 @@ pub fn path_create_directory( let mut cur_dir_inode = working_dir.inode; for comp in &path_vec { debug!("Creating dir {}", comp); - match &mut state.fs.inodes[cur_dir_inode].kind { + let mut guard = inodes.arena[cur_dir_inode].write(); + match guard.deref_mut() { Kind::Dir { ref mut entries, path, @@ -1397,11 +1477,22 @@ pub fn path_create_directory( cur_dir_inode = *child; } else { let mut adjusted_path = path.clone(); + drop(guard); + // TODO: double check this doesn't risk breaking the sandbox adjusted_path.push(comp); - if adjusted_path.exists() && !adjusted_path.is_dir() { - return __WASI_ENOTDIR; - } else if !adjusted_path.exists() { + if let Ok(adjusted_path_stat) = path_filestat_get_internal( + memory, + state, + inodes.deref_mut(), + fd, + 0, + &adjusted_path.to_string_lossy(), + ) { + if adjusted_path_stat.st_filetype != __WASI_FILETYPE_DIRECTORY { + return __WASI_ENOTDIR; + } + } else { wasi_try!(state.fs_create_dir(&adjusted_path)); } let kind = Kind::Dir { @@ -1409,13 +1500,22 @@ pub fn path_create_directory( path: adjusted_path, entries: Default::default(), }; - let new_inode = wasi_try!(state.fs.create_inode(kind, false, comp.to_string())); + let new_inode = wasi_try!(state.fs.create_inode( + inodes.deref_mut(), + kind, + false, + comp.to_string() + )); + // reborrow to insert - if let Kind::Dir { - ref mut entries, .. - } = &mut state.fs.inodes[cur_dir_inode].kind { - entries.insert(comp.to_string(), new_inode); + let mut guard = inodes.arena[cur_dir_inode].write(); + if let Kind::Dir { + ref mut entries, .. + } = guard.deref_mut() + { + entries.insert(comp.to_string(), new_inode); + } } cur_dir_inode = new_inode; } @@ -1443,7 +1543,7 @@ pub fn path_create_directory( /// - `__wasi_file_stat_t *buf` /// The location where the metadata will be stored pub fn path_filestat_get( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, @@ -1451,36 +1551,72 @@ pub fn path_filestat_get( buf: WasmPtr<__wasi_filestat_t>, ) -> __wasi_errno_t { debug!("wasi::path_filestat_get"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); - - let root_dir = wasi_try!(state.fs.get_fd(fd)); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); - if !has_rights(root_dir.rights, __WASI_RIGHT_PATH_FILESTAT_GET) { - return __WASI_EACCES; - } let path_string = unsafe { get_input_str!(memory, path, path_len) }; - debug!("=> base_fd: {}, path: {}", fd, &path_string); - - let file_inode = wasi_try!(state.fs.get_inode_at_path( + let stat = wasi_try!(path_filestat_get_internal( + memory, + state, + inodes.deref_mut(), fd, - &path_string, - flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, + flags, + &path_string )); - let stat = if state.fs.inodes[file_inode].is_preopened { - state.fs.inodes[file_inode].stat - } else { - wasi_try!(state - .fs - .get_stat_for_kind(&state.fs.inodes[file_inode].kind) - .ok_or(__WASI_EIO)) - }; wasi_try_mem!(buf.deref(memory).write(stat)); __WASI_ESUCCESS } +/// ### `path_filestat_get()` +/// Access metadata about a file or directory +/// Inputs: +/// - `__wasi_fd_t fd` +/// The directory that `path` is relative to +/// - `__wasi_lookupflags_t flags` +/// Flags to control how `path` is understood +/// - `const char *path` +/// String containing the file path +/// - `u32 path_len` +/// The length of the `path` string +/// Output: +/// - `__wasi_file_stat_t *buf` +/// The location where the metadata will be stored +pub fn path_filestat_get_internal( + memory: &Memory, + state: &WasiState, + inodes: &mut crate::WasiInodes, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path_string: &str, +) -> Result<__wasi_filestat_t, __wasi_errno_t> { + let root_dir = state.fs.get_fd(fd)?; + + if !has_rights(root_dir.rights, __WASI_RIGHT_PATH_FILESTAT_GET) { + return Err(__WASI_EACCES); + } + debug!("=> base_fd: {}, path: {}", fd, path_string); + + let file_inode = state.fs.get_inode_at_path( + inodes, + fd, + path_string, + flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, + )?; + if inodes.arena[file_inode].is_preopened { + Ok(inodes.arena[file_inode] + .stat + .read() + .unwrap() + .deref() + .clone()) + } else { + let guard = inodes.arena[file_inode].read(); + state.fs.get_stat_for_kind(inodes.deref(), guard.deref()) + } +} + /// ### `path_filestat_set_times()` /// Update time metadata on a file or directory /// Inputs: @@ -1499,7 +1635,7 @@ pub fn path_filestat_get( /// - `__wasi_fstflags_t fst_flags` /// A bitmask controlling which attributes are set pub fn path_filestat_set_times( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, @@ -1509,7 +1645,7 @@ pub fn path_filestat_set_times( fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { debug!("wasi::path_filestat_set_times"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); let fd_inode = fd_entry.inode; if !has_rights(fd_entry.rights, __WASI_RIGHT_PATH_FILESTAT_SET_TIMES) { @@ -1526,16 +1662,17 @@ pub fn path_filestat_set_times( debug!("=> base_fd: {}, path: {}", fd, &path_string); let file_inode = wasi_try!(state.fs.get_inode_at_path( + inodes.deref_mut(), fd, &path_string, flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, )); - let stat = wasi_try!(state - .fs - .get_stat_for_kind(&state.fs.inodes[file_inode].kind) - .ok_or(__WASI_EIO)); + let stat = { + let guard = inodes.arena[file_inode].read(); + wasi_try!(state.fs.get_stat_for_kind(inodes.deref(), guard.deref())) + }; - let inode = &mut state.fs.inodes[fd_inode]; + let inode = &inodes.arena[fd_inode]; if fst_flags & __WASI_FILESTAT_SET_ATIM != 0 || fst_flags & __WASI_FILESTAT_SET_ATIM_NOW != 0 { let time_to_set = if fst_flags & __WASI_FILESTAT_SET_ATIM != 0 { @@ -1543,7 +1680,7 @@ pub fn path_filestat_set_times( } else { wasi_try!(get_current_time_in_nanos()) }; - inode.stat.st_atim = time_to_set; + inode.stat.write().unwrap().st_atim = time_to_set; } if fst_flags & __WASI_FILESTAT_SET_MTIM != 0 || fst_flags & __WASI_FILESTAT_SET_MTIM_NOW != 0 { let time_to_set = if fst_flags & __WASI_FILESTAT_SET_MTIM != 0 { @@ -1551,7 +1688,7 @@ pub fn path_filestat_set_times( } else { wasi_try!(get_current_time_in_nanos()) }; - inode.stat.st_mtim = time_to_set; + inode.stat.write().unwrap().st_mtim = time_to_set; } __WASI_ESUCCESS @@ -1575,7 +1712,7 @@ pub fn path_filestat_set_times( /// - `u32 old_path_len` /// Length of the `new_path` string pub fn path_link( - env: &WasiEnv, + thread: &WasiThread, old_fd: __wasi_fd_t, old_flags: __wasi_lookupflags_t, old_path: WasmPtr, @@ -1588,7 +1725,7 @@ pub fn path_link( if old_flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 { debug!(" - will follow symlinks when opening path"); } - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); let old_path_str = unsafe { get_input_str!(memory, old_path, old_path_len) }; let new_path_str = unsafe { get_input_str!(memory, new_path, new_path_len) }; let source_fd = wasi_try!(state.fs.get_fd(old_fd)); @@ -1605,30 +1742,39 @@ pub fn path_link( } let source_inode = wasi_try!(state.fs.get_inode_at_path( + inodes.deref_mut(), old_fd, &old_path_str, old_flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, )); let target_path_arg = std::path::PathBuf::from(&new_path_str); - let (target_parent_inode, new_entry_name) = - wasi_try!(state - .fs - .get_parent_inode_at_path(new_fd, &target_path_arg, false)); + let (target_parent_inode, new_entry_name) = wasi_try!(state.fs.get_parent_inode_at_path( + inodes.deref_mut(), + new_fd, + &target_path_arg, + false + )); - if state.fs.inodes[source_inode].stat.st_nlink == __wasi_linkcount_t::max_value() { + if inodes.arena[source_inode].stat.write().unwrap().st_nlink == __wasi_linkcount_t::max_value() + { return __WASI_EMLINK; } - match &mut state.fs.inodes[target_parent_inode].kind { - Kind::Dir { entries, .. } => { - if entries.contains_key(&new_entry_name) { - return __WASI_EEXIST; + { + let mut guard = inodes.arena[target_parent_inode].write(); + match guard.deref_mut() { + Kind::Dir { entries, .. } => { + if entries.contains_key(&new_entry_name) { + return __WASI_EEXIST; + } + entries.insert(new_entry_name, source_inode); + } + Kind::Root { .. } => return __WASI_EINVAL, + Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => { + return __WASI_ENOTDIR } - entries.insert(new_entry_name, source_inode); } - Kind::Root { .. } => return __WASI_EINVAL, - Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => return __WASI_ENOTDIR, } - state.fs.inodes[source_inode].stat.st_nlink += 1; + inodes.arena[source_inode].stat.write().unwrap().st_nlink += 1; __WASI_ESUCCESS } @@ -1658,7 +1804,7 @@ pub fn path_link( /// Possible Errors: /// - `__WASI_EACCES`, `__WASI_EBADF`, `__WASI_EFAULT`, `__WASI_EFBIG?`, `__WASI_EINVAL`, `__WASI_EIO`, `__WASI_ELOOP`, `__WASI_EMFILE`, `__WASI_ENAMETOOLONG?`, `__WASI_ENFILE`, `__WASI_ENOENT`, `__WASI_ENOTDIR`, `__WASI_EROFS`, and `__WASI_ENOTCAPABLE` pub fn path_open( - env: &WasiEnv, + thread: &WasiThread, dirfd: __wasi_fd_t, dirflags: __wasi_lookupflags_t, path: WasmPtr, @@ -1673,7 +1819,7 @@ pub fn path_open( if dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 { debug!(" - will follow symlinks when opening path"); } - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); /* TODO: find actual upper bound on name size (also this is a path, not a name :think-fish:) */ if path_len > 1024 * 1024 { return __WASI_ENAMETOOLONG; @@ -1700,6 +1846,7 @@ pub fn path_open( let path_arg = std::path::PathBuf::from(&path_string); let maybe_inode = state.fs.get_inode_at_path( + inodes.deref_mut(), dirfd, &path_string, dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, @@ -1713,7 +1860,8 @@ pub fn path_open( let mut open_options = state.fs_new_open_options(); let inode = if let Ok(inode) = maybe_inode { // Happy path, we found the file we're trying to open - match &mut state.fs.inodes[inode].kind { + let mut guard = inodes.arena[inode].write(); + match guard.deref_mut() { Kind::File { ref mut handle, path, @@ -1728,9 +1876,10 @@ pub fn path_open( if o_flags & __WASI_O_DIRECTORY != 0 { return __WASI_ENOTDIR; } - if o_flags & __WASI_O_EXCL != 0 && path.exists() { + if o_flags & __WASI_O_EXCL != 0 { return __WASI_EEXIST; } + let write_permission = adjusted_rights & __WASI_RIGHT_FD_WRITE != 0; // append, truncate, and create all require the permission to write let (append_permission, truncate_permission, create_permission) = @@ -1765,12 +1914,7 @@ pub fn path_open( .map_err(fs_error_into_wasi_err))); } Kind::Buffer { .. } => unimplemented!("wasi::path_open for Buffer type files"), - Kind::Dir { .. } | Kind::Root { .. } => { - // TODO: adjust these to be correct - if o_flags & __WASI_O_EXCL != 0 && path_arg.exists() { - return __WASI_EEXIST; - } - } + Kind::Dir { .. } | Kind::Root { .. } => {} Kind::Symlink { base_po_dir, path_to_symlink, @@ -1793,18 +1937,22 @@ pub fn path_open( // strip end file name let (parent_inode, new_entity_name) = wasi_try!(state.fs.get_parent_inode_at_path( + inodes.deref_mut(), dirfd, &path_arg, dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 )); - let new_file_host_path = match &state.fs.inodes[parent_inode].kind { - Kind::Dir { path, .. } => { - let mut new_path = path.clone(); - new_path.push(&new_entity_name); - new_path + let new_file_host_path = { + let guard = inodes.arena[parent_inode].read(); + match guard.deref() { + Kind::Dir { path, .. } => { + let mut new_path = path.clone(); + new_path.push(&new_entity_name); + new_path + } + Kind::Root { .. } => return __WASI_EACCES, + _ => return __WASI_EINVAL, } - Kind::Root { .. } => return __WASI_EACCES, - _ => return __WASI_EINVAL, }; // once we got the data we need from the parent, we lookup the host file // todo: extra check that opening with write access is okay @@ -1832,14 +1980,22 @@ pub fn path_open( path: new_file_host_path, fd: None, }; - wasi_try!(state.fs.create_inode(kind, false, new_entity_name.clone())) + wasi_try!(state.fs.create_inode( + inodes.deref_mut(), + kind, + false, + new_entity_name.clone() + )) }; - if let Kind::Dir { - ref mut entries, .. - } = &mut state.fs.inodes[parent_inode].kind { - entries.insert(new_entity_name, new_inode); + let mut guard = inodes.arena[parent_inode].write(); + if let Kind::Dir { + ref mut entries, .. + } = guard.deref_mut() + { + entries.insert(new_entity_name, new_inode); + } } new_inode @@ -1848,10 +2004,9 @@ pub fn path_open( } }; - debug!( - "inode {:?} value {:#?} found!", - inode, state.fs.inodes[inode] - ); + { + debug!("inode {:?} value {:#?} found!", inode, inodes.arena[inode]); + } // TODO: check and reduce these // TODO: ensure a mutable fd to root can never be opened @@ -1886,7 +2041,7 @@ pub fn path_open( /// - `u32 buf_used` /// The number of bytes written to `buf` pub fn path_readlink( - env: &WasiEnv, + thread: &WasiThread, dir_fd: __wasi_fd_t, path: WasmPtr, path_len: u32, @@ -1895,30 +2050,36 @@ pub fn path_readlink( buf_used: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::path_readlink"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); - let base_dir = wasi_try!(state.fs.fd_map.get(&dir_fd).ok_or(__WASI_EBADF)); + let base_dir = wasi_try!(state.fs.get_fd(dir_fd)); if !has_rights(base_dir.rights, __WASI_RIGHT_PATH_READLINK) { return __WASI_EACCES; } let path_str = unsafe { get_input_str!(memory, path, path_len) }; - let inode = wasi_try!(state.fs.get_inode_at_path(dir_fd, &path_str, false)); - - if let Kind::Symlink { relative_path, .. } = &state.fs.inodes[inode].kind { - let rel_path_str = relative_path.to_string_lossy(); - debug!("Result => {:?}", rel_path_str); - let bytes = rel_path_str.as_bytes(); - if bytes.len() >= buf_len as usize { - return __WASI_EOVERFLOW; - } + let inode = wasi_try!(state + .fs + .get_inode_at_path(inodes.deref_mut(), dir_fd, &path_str, false)); - let out = wasi_try_mem!(buf.slice(memory, bytes.len() as u32)); - wasi_try_mem!(out.write_slice(bytes)); - // should we null terminate this? + { + let guard = inodes.arena[inode].read(); + if let Kind::Symlink { relative_path, .. } = guard.deref() { + let rel_path_str = relative_path.to_string_lossy(); + debug!("Result => {:?}", rel_path_str); + let bytes = rel_path_str.bytes(); + if bytes.len() >= buf_len as usize { + return __WASI_EOVERFLOW; + } + let bytes: Vec<_> = bytes.collect(); - wasi_try_mem!(buf_used.deref(memory).write(bytes.len() as u32)); - } else { - return __WASI_EINVAL; + let out = wasi_try_mem!(buf.slice(memory, bytes.len() as u32)); + wasi_try_mem!(out.write_slice(&bytes[..])); + // should we null terminate this? + + wasi_try_mem!(buf_used.deref(memory).write(bytes.len() as u32)); + } else { + return __WASI_EINVAL; + } } __WASI_ESUCCESS @@ -1926,59 +2087,69 @@ pub fn path_readlink( /// Returns __WASI_ENOTEMTPY if directory is not empty pub fn path_remove_directory( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, path: WasmPtr, path_len: u32, ) -> __wasi_errno_t { // TODO check if fd is a dir, ensure it's within sandbox, etc. debug!("wasi::path_remove_directory"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); - let base_dir = wasi_try!(state.fs.fd_map.get(&fd), __WASI_EBADF); + let base_dir = wasi_try!(state.fs.get_fd(fd)); let path_str = unsafe { get_input_str!(memory, path, path_len) }; - let inode = wasi_try!(state.fs.get_inode_at_path(fd, &path_str, false)); - let (parent_inode, childs_name) = - wasi_try!(state - .fs - .get_parent_inode_at_path(fd, std::path::Path::new(&path_str), false)); + let inode = wasi_try!(state + .fs + .get_inode_at_path(inodes.deref_mut(), fd, &path_str, false)); + let (parent_inode, childs_name) = wasi_try!(state.fs.get_parent_inode_at_path( + inodes.deref_mut(), + fd, + std::path::Path::new(&path_str), + false + )); - let host_path_to_remove = match &state.fs.inodes[inode].kind { - Kind::Dir { entries, path, .. } => { - if !entries.is_empty() || wasi_try!(state.fs_read_dir(path)).count() != 0 { - return __WASI_ENOTEMPTY; + let host_path_to_remove = { + let guard = inodes.arena[inode].read(); + match guard.deref() { + Kind::Dir { entries, path, .. } => { + if !entries.is_empty() || wasi_try!(state.fs_read_dir(path)).count() != 0 { + return __WASI_ENOTEMPTY; + } + path.clone() } - path.clone() + Kind::Root { .. } => return __WASI_EACCES, + _ => return __WASI_ENOTDIR, } - Kind::Root { .. } => return __WASI_EACCES, - _ => return __WASI_ENOTDIR, }; - match &mut state.fs.inodes[parent_inode].kind { - Kind::Dir { - ref mut entries, .. - } => { - let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(__WASI_EINVAL)); - // TODO: make this a debug assert in the future - assert!(inode == removed_inode); + { + let mut guard = inodes.arena[parent_inode].write(); + match guard.deref_mut() { + Kind::Dir { + ref mut entries, .. + } => { + let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(__WASI_EINVAL)); + // TODO: make this a debug assert in the future + assert!(inode == removed_inode); + } + Kind::Root { .. } => return __WASI_EACCES, + _ => unreachable!( + "Internal logic error in wasi::path_remove_directory, parent is not a directory" + ), } - Kind::Root { .. } => return __WASI_EACCES, - _ => unreachable!( - "Internal logic error in wasi::path_remove_directory, parent is not a directory" - ), } - if state.fs_remove_dir(host_path_to_remove).is_err() { + if let Err(err) = state.fs_remove_dir(host_path_to_remove) { // reinsert to prevent FS from being in bad state + let mut guard = inodes.arena[parent_inode].write(); if let Kind::Dir { ref mut entries, .. - } = &mut state.fs.inodes[parent_inode].kind + } = guard.deref_mut() { entries.insert(childs_name, inode); } - // TODO: more intelligently return error value by inspecting returned error value - return __WASI_EIO; + return err; } __WASI_ESUCCESS @@ -2000,7 +2171,7 @@ pub fn path_remove_directory( /// - `u32 new_path_len` /// The number of bytes to read from `new_path` pub fn path_rename( - env: &WasiEnv, + thread: &WasiThread, old_fd: __wasi_fd_t, old_path: WasmPtr, old_path_len: u32, @@ -2012,7 +2183,7 @@ pub fn path_rename( "wasi::path_rename: old_fd = {}, new_fd = {}", old_fd, new_fd ); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); let source_str = unsafe { get_input_str!(memory, old_path, old_path_len) }; let source_path = std::path::Path::new(&source_str); let target_str = unsafe { get_input_str!(memory, new_path, new_path_len) }; @@ -2031,84 +2202,110 @@ pub fn path_rename( } let (source_parent_inode, source_entry_name) = - wasi_try!(state.fs.get_parent_inode_at_path(old_fd, source_path, true)); + wasi_try!(state + .fs + .get_parent_inode_at_path(inodes.deref_mut(), old_fd, source_path, true)); let (target_parent_inode, target_entry_name) = - wasi_try!(state.fs.get_parent_inode_at_path(new_fd, target_path, true)); + wasi_try!(state + .fs + .get_parent_inode_at_path(inodes.deref_mut(), new_fd, target_path, true)); - let host_adjusted_target_path = match &state.fs.inodes[target_parent_inode].kind { - Kind::Dir { entries, path, .. } => { - if entries.contains_key(&target_entry_name) { - return __WASI_EEXIST; + let host_adjusted_target_path = { + let guard = inodes.arena[target_parent_inode].read(); + match guard.deref() { + Kind::Dir { entries, path, .. } => { + if entries.contains_key(&target_entry_name) { + return __WASI_EEXIST; + } + let mut out_path = path.clone(); + out_path.push(std::path::Path::new(&target_entry_name)); + out_path + } + Kind::Root { .. } => return __WASI_ENOTCAPABLE, + Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => { + unreachable!("Fatal internal logic error: parent of inode is not a directory") } - let mut out_path = path.clone(); - out_path.push(std::path::Path::new(&target_entry_name)); - out_path - } - Kind::Root { .. } => return __WASI_ENOTCAPABLE, - Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => { - unreachable!("Fatal internal logic error: parent of inode is not a directory") } }; - let source_entry = match &mut state.fs.inodes[source_parent_inode].kind { - Kind::Dir { entries, .. } => { - wasi_try!(entries.remove(&source_entry_name), __WASI_ENOENT) - } - Kind::Root { .. } => return __WASI_ENOTCAPABLE, - Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => { - unreachable!("Fatal internal logic error: parent of inode is not a directory") + let source_entry = { + let mut guard = inodes.arena[source_parent_inode].write(); + match guard.deref_mut() { + Kind::Dir { entries, .. } => { + wasi_try!(entries.remove(&source_entry_name).ok_or(__WASI_ENOENT)) + } + Kind::Root { .. } => return __WASI_ENOTCAPABLE, + Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => { + unreachable!("Fatal internal logic error: parent of inode is not a directory") + } } }; - match &mut state.fs.inodes[source_entry].kind { - Kind::File { - handle, ref path, .. - } => { - // TODO: investigate why handle is not always there, it probably should be. - // My best guess is the fact that a handle means currently open and a path - // just means reference to host file on disk. But ideally those concepts - // could just be unified even if there's a `Box` which just - // implements the logic of "I'm not actually a file, I'll try to be as needed". - let result = if let Some(h) = handle { - state.fs_rename(&source_path, &host_adjusted_target_path) - } else { - let path_clone = path.clone(); - let out = state.fs_rename(&path_clone, &host_adjusted_target_path); - if let Kind::File { ref mut path, .. } = &mut state.fs.inodes[source_entry].kind { - *path = host_adjusted_target_path; + { + let mut guard = inodes.arena[source_entry].write(); + match guard.deref_mut() { + Kind::File { + handle, ref path, .. + } => { + // TODO: investigate why handle is not always there, it probably should be. + // My best guess is the fact that a handle means currently open and a path + // just means reference to host file on disk. But ideally those concepts + // could just be unified even if there's a `Box` which just + // implements the logic of "I'm not actually a file, I'll try to be as needed". + let result = if let Some(h) = handle { + drop(guard); + state.fs_rename(&source_path, &host_adjusted_target_path) } else { - unreachable!() + let path_clone = path.clone(); + drop(guard); + let out = state.fs_rename(&path_clone, &host_adjusted_target_path); + { + let mut guard = inodes.arena[source_entry].write(); + if let Kind::File { ref mut path, .. } = guard.deref_mut() { + *path = host_adjusted_target_path; + } else { + unreachable!() + } + } + out + }; + // if the above operation failed we have to revert the previous change and then fail + if let Err(e) = result.clone() { + let mut guard = inodes.arena[source_parent_inode].write(); + if let Kind::Dir { entries, .. } = guard.deref_mut() { + entries.insert(source_entry_name, source_entry); + return e; + } } - out - }; - // if the above operation failed we have to revert the previous change and then fail - if let Err(e) = result { - if let Kind::Dir { entries, .. } = &mut state.fs.inodes[source_parent_inode].kind { - entries.insert(source_entry_name, source_entry); + } + Kind::Dir { ref path, .. } => { + let cloned_path = path.clone(); + if let Err(e) = state.fs_rename(cloned_path, &host_adjusted_target_path) { return e; } + { + drop(guard); + let mut guard = inodes.arena[source_entry].write(); + if let Kind::Dir { path, .. } = guard.deref_mut() { + *path = host_adjusted_target_path; + } + } } + Kind::Buffer { .. } => {} + Kind::Symlink { .. } => {} + Kind::Root { .. } => unreachable!("The root can not be moved"), } - Kind::Dir { ref path, .. } => { - let cloned_path = path.clone(); - if let Err(e) = state.fs_rename(cloned_path, &host_adjusted_target_path) { - return e; - } - if let Kind::Dir { path, .. } = &mut state.fs.inodes[source_entry].kind { - *path = host_adjusted_target_path; - } - } - Kind::Buffer { .. } => {} - Kind::Symlink { .. } => {} - Kind::Root { .. } => unreachable!("The root can not be moved"), } - if let Kind::Dir { entries, .. } = &mut state.fs.inodes[target_parent_inode].kind { - let result = entries.insert(target_entry_name, source_entry); - assert!( - result.is_none(), - "Fatal error: race condition on filesystem detected or internal logic error" - ); + { + let mut guard = inodes.arena[target_parent_inode].write(); + if let Kind::Dir { entries, .. } = guard.deref_mut() { + let result = entries.insert(target_entry_name, source_entry); + assert!( + result.is_none(), + "Fatal error: race condition on filesystem detected or internal logic error" + ); + } } __WASI_ESUCCESS @@ -2128,7 +2325,7 @@ pub fn path_rename( /// - `u32 new_path_len` /// The number of bytes to read from `new_path` pub fn path_symlink( - env: &WasiEnv, + thread: &WasiThread, old_path: WasmPtr, old_path_len: u32, fd: __wasi_fd_t, @@ -2136,7 +2333,7 @@ pub fn path_symlink( new_path_len: u32, ) -> __wasi_errno_t { debug!("wasi::path_symlink"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); let old_path_str = unsafe { get_input_str!(memory, old_path, old_path_len) }; let new_path_str = unsafe { get_input_str!(memory, new_path, new_path_len) }; let base_fd = wasi_try!(state.fs.get_fd(fd)); @@ -2146,23 +2343,34 @@ pub fn path_symlink( // get the depth of the parent + 1 (UNDER INVESTIGATION HMMMMMMMM THINK FISH ^ THINK FISH) let old_path_path = std::path::Path::new(&old_path_str); - let (source_inode, _) = wasi_try!(state.fs.get_parent_inode_at_path(fd, old_path_path, true)); - let depth = wasi_try!(state.fs.path_depth_from_fd(fd, source_inode)) - 1; + let (source_inode, _) = + wasi_try!(state + .fs + .get_parent_inode_at_path(inodes.deref_mut(), fd, old_path_path, true)); + let depth = wasi_try!(state + .fs + .path_depth_from_fd(inodes.deref(), fd, source_inode)) + - 1; let new_path_path = std::path::Path::new(&new_path_str); let (target_parent_inode, entry_name) = - wasi_try!(state.fs.get_parent_inode_at_path(fd, new_path_path, true)); + wasi_try!(state + .fs + .get_parent_inode_at_path(inodes.deref_mut(), fd, new_path_path, true)); // short circuit if anything is wrong, before we create an inode - match &state.fs.inodes[target_parent_inode].kind { - Kind::Dir { entries, .. } => { - if entries.contains_key(&entry_name) { - return __WASI_EEXIST; + { + let guard = inodes.arena[target_parent_inode].read(); + match guard.deref() { + Kind::Dir { entries, .. } => { + if entries.contains_key(&entry_name) { + return __WASI_EEXIST; + } + } + Kind::Root { .. } => return __WASI_ENOTCAPABLE, + Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => { + unreachable!("get_parent_inode_at_path returned something other than a Dir or Root") } - } - Kind::Root { .. } => return __WASI_ENOTCAPABLE, - Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => { - unreachable!("get_parent_inode_at_path returned something other than a Dir or Root") } } @@ -2183,15 +2391,21 @@ pub fn path_symlink( path_to_symlink: std::path::PathBuf::from(new_path_str), relative_path, }; - let new_inode = state - .fs - .create_inode_with_default_stat(kind, false, entry_name.clone()); + let new_inode = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + kind, + false, + entry_name.clone(), + ); - if let Kind::Dir { - ref mut entries, .. - } = &mut state.fs.inodes[target_parent_inode].kind { - entries.insert(entry_name, new_inode); + let mut guard = inodes.arena[target_parent_inode].write(); + if let Kind::Dir { + ref mut entries, .. + } = guard.deref_mut() + { + entries.insert(entry_name, new_inode); + } } __WASI_ESUCCESS @@ -2207,80 +2421,95 @@ pub fn path_symlink( /// - `u32 path_len` /// The number of bytes in the `path` array pub fn path_unlink_file( - env: &WasiEnv, + thread: &WasiThread, fd: __wasi_fd_t, path: WasmPtr, path_len: u32, ) -> __wasi_errno_t { debug!("wasi::path_unlink_file"); - let (memory, mut state) = env.get_memory_and_wasi_state(0); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); - let base_dir = wasi_try!(state.fs.fd_map.get(&fd).ok_or(__WASI_EBADF)); + let base_dir = wasi_try!(state.fs.get_fd(fd)); if !has_rights(base_dir.rights, __WASI_RIGHT_PATH_UNLINK_FILE) { return __WASI_EACCES; } let path_str = unsafe { get_input_str!(memory, path, path_len) }; debug!("Requested file: {}", path_str); - let inode = wasi_try!(state.fs.get_inode_at_path(fd, &path_str, false)); - let (parent_inode, childs_name) = - wasi_try!(state - .fs - .get_parent_inode_at_path(fd, std::path::Path::new(&path_str), false)); + let inode = wasi_try!(state + .fs + .get_inode_at_path(inodes.deref_mut(), fd, &path_str, false)); + let (parent_inode, childs_name) = wasi_try!(state.fs.get_parent_inode_at_path( + inodes.deref_mut(), + fd, + std::path::Path::new(&path_str), + false + )); - let removed_inode = match &mut state.fs.inodes[parent_inode].kind { - Kind::Dir { - ref mut entries, .. - } => { - let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(__WASI_EINVAL)); - // TODO: make this a debug assert in the future - assert!(inode == removed_inode); - debug_assert!(state.fs.inodes[inode].stat.st_nlink > 0); - removed_inode + let removed_inode = { + let mut guard = inodes.arena[parent_inode].write(); + match guard.deref_mut() { + Kind::Dir { + ref mut entries, .. + } => { + let removed_inode = wasi_try!(entries.remove(&childs_name).ok_or(__WASI_EINVAL)); + // TODO: make this a debug assert in the future + assert!(inode == removed_inode); + debug_assert!(inodes.arena[inode].stat.read().unwrap().st_nlink > 0); + removed_inode + } + Kind::Root { .. } => return __WASI_EACCES, + _ => unreachable!( + "Internal logic error in wasi::path_unlink_file, parent is not a directory" + ), } - Kind::Root { .. } => return __WASI_EACCES, - _ => unreachable!( - "Internal logic error in wasi::path_unlink_file, parent is not a directory" - ), }; - state.fs.inodes[removed_inode].stat.st_nlink -= 1; - if state.fs.inodes[removed_inode].stat.st_nlink == 0 { - match &mut state.fs.inodes[removed_inode].kind { - Kind::File { handle, path, .. } => { - if let Some(h) = handle { - wasi_try!(h.unlink().map_err(fs_error_into_wasi_err)); - } else { - // File is closed - // problem with the abstraction, we can't call unlink because there's no handle - // drop mutable borrow on `path` - let path = path.clone(); - wasi_try!(state.fs_remove_file(path)); + let st_nlink = { + let mut guard = inodes.arena[removed_inode].stat.write().unwrap(); + guard.st_nlink -= 1; + guard.st_nlink + }; + if st_nlink == 0 { + { + let mut guard = inodes.arena[removed_inode].write(); + match guard.deref_mut() { + Kind::File { handle, path, .. } => { + if let Some(h) = handle { + wasi_try!(h.unlink().map_err(fs_error_into_wasi_err)); + } else { + // File is closed + // problem with the abstraction, we can't call unlink because there's no handle + // drop mutable borrow on `path` + let path = path.clone(); + wasi_try!(state.fs_remove_file(path)); + } } + Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, + Kind::Symlink { .. } => { + // TODO: actually delete real symlinks and do nothing for virtual symlinks + } + _ => unimplemented!("wasi::path_unlink_file for Buffer"), } - Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, - Kind::Symlink { .. } => { - // TODO: actually delete real symlinks and do nothing for virtual symlinks - } - _ => unimplemented!("wasi::path_unlink_file for Buffer"), } // TODO: test this on Windows and actually make it portable // make the file an orphan fd if the fd is still open - let fd_is_orphaned = if let Kind::File { handle, .. } = &state.fs.inodes[removed_inode].kind - { - handle.is_some() - } else { - false + let fd_is_orphaned = { + let guard = inodes.arena[removed_inode].read(); + if let Kind::File { handle, .. } = guard.deref() { + handle.is_some() + } else { + false + } }; - let removed_inode_val = unsafe { state.fs.remove_inode(removed_inode) }; + let removed_inode_val = unsafe { state.fs.remove_inode(inodes.deref_mut(), removed_inode) }; assert!( removed_inode_val.is_some(), "Inode could not be removed because it doesn't exist" ); if fd_is_orphaned { - state - .fs + inodes .orphan_fds .insert(removed_inode, removed_inode_val.unwrap()); } @@ -2301,41 +2530,39 @@ pub fn path_unlink_file( /// Output: /// - `u32 nevents` /// The number of events seen -#[cfg(not(feature = "js"))] pub fn poll_oneoff( - env: &WasiEnv, + thread: &WasiThread, in_: WasmPtr<__wasi_subscription_t>, out_: WasmPtr<__wasi_event_t>, nsubscriptions: u32, nevents: WasmPtr, -) -> __wasi_errno_t { - debug!("wasi::poll_oneoff"); - debug!(" => nsubscriptions = {}", nsubscriptions); - let (memory, mut state) = env.get_memory_and_wasi_state(0); +) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::poll_oneoff"); + trace!(" => nsubscriptions = {}", nsubscriptions); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); - let subscription_array = wasi_try_mem!(in_.slice(memory, nsubscriptions)); - let event_array = wasi_try_mem!(out_.slice(memory, nsubscriptions)); + let subscription_array = wasi_try_mem_ok!(in_.slice(memory, nsubscriptions)); + let event_array = wasi_try_mem_ok!(out_.slice(memory, nsubscriptions)); let mut events_seen = 0; let out_ptr = nevents.deref(memory); - let mut fds = vec![]; + let mut fd_guards = vec![]; let mut clock_subs = vec![]; let mut in_events = vec![]; - let mut total_ns_slept = 0; + let mut time_to_sleep = Duration::from_millis(5); for sub in subscription_array.iter() { - let s: WasiSubscription = wasi_try!(wasi_try_mem!(sub.read()).try_into()); + let s: WasiSubscription = wasi_try_ok!(wasi_try_mem_ok!(sub.read()).try_into()); let mut peb = PollEventBuilder::new(); - let mut ns_to_sleep = 0; - + let fd = match s.event_type { EventType::Read(__wasi_subscription_fs_readwrite_t { fd }) => { match fd { __WASI_STDIN_FILENO | __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => (), _ => { - let fd_entry = wasi_try!(state.fs.get_fd(fd)); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), thread); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_READ) { - return __WASI_EACCES; + return Ok(__WASI_EACCES); } } } @@ -2346,10 +2573,9 @@ pub fn poll_oneoff( match fd { __WASI_STDIN_FILENO | __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => (), _ => { - let fd_entry = wasi_try!(state.fs.get_fd(fd)); - + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), thread); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_WRITE) { - return __WASI_EACCES; + return Ok(__WASI_EACCES); } } } @@ -2357,11 +2583,13 @@ pub fn poll_oneoff( Some(fd) } EventType::Clock(clock_info) => { - if clock_info.clock_id == __WASI_CLOCK_REALTIME { + if clock_info.clock_id == __WASI_CLOCK_REALTIME + || clock_info.clock_id == __WASI_CLOCK_MONOTONIC + { // this is a hack // TODO: do this properly - ns_to_sleep = clock_info.timeout; - clock_subs.push(clock_info); + time_to_sleep = Duration::from_nanos(clock_info.timeout); + clock_subs.push((clock_info, s.user_data)); None } else { unimplemented!("Polling not implemented for clocks yet"); @@ -2370,64 +2598,104 @@ pub fn poll_oneoff( }; if let Some(fd) = fd { - let wasi_file_ref: &dyn VirtualFile = match fd { - __WASI_STDERR_FILENO => wasi_try!( - wasi_try!(state.fs.stderr().map_err(fs_error_into_wasi_err)).as_ref(), - __WASI_EBADF - ) - .as_ref(), - __WASI_STDIN_FILENO => wasi_try!( - wasi_try!(state.fs.stdin().map_err(fs_error_into_wasi_err)).as_ref(), - __WASI_EBADF - ) - .as_ref(), - __WASI_STDOUT_FILENO => wasi_try!( - wasi_try!(state.fs.stdout().map_err(fs_error_into_wasi_err)).as_ref(), - __WASI_EBADF - ) - .as_ref(), + let wasi_file_ref = match fd { + __WASI_STDERR_FILENO => { + wasi_try_ok!( + inodes + .stderr(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ) + } + __WASI_STDIN_FILENO => { + wasi_try_ok!( + inodes + .stdin(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ) + } + __WASI_STDOUT_FILENO => { + wasi_try_ok!( + inodes + .stdout(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ) + } _ => { - let fd_entry = wasi_try!(state.fs.get_fd(fd)); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), thread); let inode = fd_entry.inode; if !has_rights(fd_entry.rights, __WASI_RIGHT_POLL_FD_READWRITE) { - return __WASI_EACCES; + return Ok(__WASI_EACCES); } - match &state.fs.inodes[inode].kind { - Kind::File { handle, .. } => { - if let Some(h) = handle { - h.as_ref() - } else { - return __WASI_EBADF; + { + let guard = inodes.arena[inode].read(); + match guard.deref() { + Kind::File { handle, .. } => { + if let Some(h) = handle { + crate::state::InodeValFileReadGuard { guard } + } else { + return Ok(__WASI_EBADF); + } + } + Kind::Dir { .. } + | Kind::Root { .. } + | Kind::Buffer { .. } + | Kind::Symlink { .. } => { + unimplemented!("polling read on non-files not yet supported") } - } - Kind::Dir { .. } - | Kind::Root { .. } - | Kind::Buffer { .. } - | Kind::Symlink { .. } => { - unimplemented!("polling read on non-files not yet supported") } } } }; - fds.push(wasi_file_ref); - } else { - let remaining_ns = ns_to_sleep as i64 - total_ns_slept as i64; - if remaining_ns > 0 { - debug!("Sleeping for {} nanoseconds", remaining_ns); - let duration = std::time::Duration::from_nanos(remaining_ns as u64); - std::thread::sleep(duration); - total_ns_slept += remaining_ns; - } + fd_guards.push(wasi_file_ref); } } + + let fds = { + let mut f = vec![]; + for fd in fd_guards.iter() { + f.push(wasi_try_ok!(fd.as_ref().ok_or(__WASI_EBADF)).deref()); + } + f + }; + let mut seen_events = vec![Default::default(); in_events.len()]; - wasi_try!(poll( - fds.as_slice(), - in_events.as_slice(), - seen_events.as_mut_slice() - ) - .map_err(fs_error_into_wasi_err)); + + let start = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let mut triggered = 0; + while triggered == 0 { + let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; + let delta = match now.checked_sub(start) { + Some(a) => Duration::from_nanos(a as u64), + None => Duration::ZERO + }; + match poll( + fds.as_slice(), + in_events.as_slice(), + seen_events.as_mut_slice(), + Duration::from_millis(1), + ) + { + Ok(0) => { + thread.yield_now()?; + }, + Ok(a) => { + triggered = a; + }, + Err(FsError::WouldBlock) => { + thread.sleep(Duration::from_millis(1))?; + }, + Err(err) => { + return Ok(fs_error_into_wasi_err(err)); + } + }; + if delta > time_to_sleep { + break; + } + } for (i, seen_event) in seen_events.into_iter().enumerate() { let mut flags = 0; @@ -2440,21 +2708,31 @@ pub fn poll_oneoff( PollEvent::PollHangUp => flags = __WASI_EVENT_FD_READWRITE_HANGUP, PollEvent::PollInvalid => error = __WASI_EINVAL, PollEvent::PollIn => { - bytes_available = - wasi_try!(fds[i].bytes_available().map_err(fs_error_into_wasi_err)); + bytes_available = wasi_try_ok!( + fds[i] + .bytes_available_read() + .map_err(fs_error_into_wasi_err), + thread + ) + .unwrap_or(0usize); error = __WASI_ESUCCESS; } PollEvent::PollOut => { - bytes_available = - wasi_try!(fds[i].bytes_available().map_err(fs_error_into_wasi_err)); + bytes_available = wasi_try_ok!( + fds[i] + .bytes_available_write() + .map_err(fs_error_into_wasi_err), + thread + ) + .unwrap_or(0usize); error = __WASI_ESUCCESS; } } } let event = __wasi_event_t { - userdata: wasi_try_mem!(subscription_array.index(i as u64).read()).userdata, + userdata: wasi_try_mem_ok!(subscription_array.index(i as u64).read()).userdata, error, - type_: wasi_try_mem!(subscription_array.index(i as u64).read()).type_, + type_: wasi_try_mem_ok!(subscription_array.index(i as u64).read()).type_, u: unsafe { __wasi_event_u { fd_readwrite: __wasi_event_fd_readwrite_t { @@ -2464,48 +2742,38 @@ pub fn poll_oneoff( } }, }; - wasi_try_mem!(event_array.index(events_seen as u64).write(event)); + wasi_try_mem_ok!(event_array.index(events_seen as u64).write(event)); events_seen += 1; } - for clock_info in clock_subs { - let event = __wasi_event_t { - // TOOD: review userdata value - userdata: 0, - error: __WASI_ESUCCESS, - type_: __WASI_EVENTTYPE_CLOCK, - u: unsafe { - __wasi_event_u { - fd_readwrite: __wasi_event_fd_readwrite_t { - nbytes: 0, - flags: 0, - }, - } - }, - }; - wasi_try_mem!(event_array.index(events_seen as u64).write(event)); - events_seen += 1; + if triggered <= 0 { + for (clock_info, userdata) in clock_subs { + let event = __wasi_event_t { + userdata, + error: __WASI_ESUCCESS, + type_: __WASI_EVENTTYPE_CLOCK, + u: unsafe { + __wasi_event_u { + fd_readwrite: __wasi_event_fd_readwrite_t { + nbytes: 0, + flags: 0, + }, + } + }, + }; + wasi_try_mem_ok!(event_array.index(events_seen as u64).write(event)); + events_seen += 1; + } } - wasi_try_mem!(out_ptr.write(events_seen as u32)); - __WASI_ESUCCESS + wasi_try_mem_ok!(out_ptr.write(events_seen as u32)); + Ok(__WASI_ESUCCESS) } -#[cfg(feature = "js")] -pub fn poll_oneoff( - env: &WasiEnv, - in_: WasmPtr<__wasi_subscription_t>, - out_: WasmPtr<__wasi_event_t>, - nsubscriptions: u32, - nevents: WasmPtr, -) -> __wasi_errno_t { - unimplemented!(); -} - -pub fn proc_exit(env: &WasiEnv, code: __wasi_exitcode_t) -> Result<(), WasiError> { +pub fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { debug!("wasi::proc_exit, {}", code); Err(WasiError::Exit(code)) } -pub fn proc_raise(env: &WasiEnv, sig: __wasi_signal_t) -> __wasi_errno_t { +pub fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { debug!("wasi::proc_raise"); unimplemented!("wasi::proc_raise") } @@ -2517,9 +2785,9 @@ pub fn proc_raise(env: &WasiEnv, sig: __wasi_signal_t) -> __wasi_errno_t { /// A pointer to a buffer where the random bytes will be written /// - `size_t buf_len` /// The number of bytes that will be written -pub fn random_get(env: &WasiEnv, buf: u32, buf_len: u32) -> __wasi_errno_t { - debug!("wasi::random_get buf_len: {}", buf_len); - let memory = env.memory(); +pub fn random_get(thread: &WasiThread, buf: u32, buf_len: u32) -> __wasi_errno_t { + trace!("wasi::random_get buf_len: {}", buf_len); + let memory = thread.memory(); let mut u8_buffer = vec![0; buf_len as usize]; let res = getrandom::getrandom(&mut u8_buffer); match res { @@ -2534,14 +2802,14 @@ pub fn random_get(env: &WasiEnv, buf: u32, buf_len: u32) -> __wasi_errno_t { /// ### `sched_yield()` /// Yields execution of the thread -pub fn sched_yield(env: &WasiEnv) -> __wasi_errno_t { - debug!("wasi::sched_yield"); - ::std::thread::yield_now(); - __WASI_ESUCCESS +pub fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::sched_yield"); + thread.yield_now()?; + Ok(__WASI_ESUCCESS) } pub fn sock_recv( - env: &WasiEnv, + thread: &WasiThread, sock: __wasi_fd_t, ri_data: WasmPtr<__wasi_iovec_t>, ri_data_len: u32, @@ -2549,21 +2817,25 @@ pub fn sock_recv( ro_datalen: WasmPtr, ro_flags: WasmPtr<__wasi_roflags_t>, ) -> __wasi_errno_t { - debug!("wasi::sock_recv"); + trace!("wasi::sock_recv"); unimplemented!("wasi::sock_recv") } pub fn sock_send( - env: &WasiEnv, + thread: &WasiThread, sock: __wasi_fd_t, si_data: WasmPtr<__wasi_ciovec_t>, si_data_len: u32, si_flags: __wasi_siflags_t, so_datalen: WasmPtr, ) -> __wasi_errno_t { - debug!("wasi::sock_send"); + trace!("wasi::sock_send"); unimplemented!("wasi::sock_send") } -pub fn sock_shutdown(env: &WasiEnv, sock: __wasi_fd_t, how: __wasi_sdflags_t) -> __wasi_errno_t { - debug!("wasi::sock_shutdown"); +pub fn sock_shutdown( + thread: &WasiThread, + sock: __wasi_fd_t, + how: __wasi_sdflags_t, +) -> __wasi_errno_t { + trace!("wasi::sock_shutdown"); unimplemented!("wasi::sock_shutdown") } diff --git a/lib/wasi/src/syscalls/unix/mod.rs b/lib/wasi/src/syscalls/unix/mod.rs index 2b494e589d5..9e3a5e35d16 100644 --- a/lib/wasi/src/syscalls/unix/mod.rs +++ b/lib/wasi/src/syscalls/unix/mod.rs @@ -9,13 +9,13 @@ use wasmer::WasmRef; pub fn platform_clock_res_get( clock_id: __wasi_clockid_t, resolution: WasmRef<__wasi_timestamp_t>, -) -> __wasi_errno_t { +) -> Result { let unix_clock_id = match clock_id { __WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC, __WASI_CLOCK_PROCESS_CPUTIME_ID => CLOCK_PROCESS_CPUTIME_ID, __WASI_CLOCK_REALTIME => CLOCK_REALTIME, __WASI_CLOCK_THREAD_CPUTIME_ID => CLOCK_THREAD_CPUTIME_ID, - _ => return __WASI_EINVAL, + _ => return Err(__WASI_EINVAL), }; let (output, timespec_out) = unsafe { @@ -27,23 +27,19 @@ pub fn platform_clock_res_get( }; let t_out = (timespec_out.tv_sec * 1_000_000_000).wrapping_add(timespec_out.tv_nsec); - wasi_try_mem!(resolution.write(t_out as __wasi_timestamp_t)); - - // TODO: map output of clock_getres to __wasi_errno_t - __WASI_ESUCCESS + Ok(t_out) } pub fn platform_clock_time_get( clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, - time: WasmRef<__wasi_timestamp_t>, -) -> __wasi_errno_t { +) -> Result { let unix_clock_id = match clock_id { __WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC, __WASI_CLOCK_PROCESS_CPUTIME_ID => CLOCK_PROCESS_CPUTIME_ID, __WASI_CLOCK_REALTIME => CLOCK_REALTIME, __WASI_CLOCK_THREAD_CPUTIME_ID => CLOCK_THREAD_CPUTIME_ID, - _ => return __WASI_EINVAL, + _ => return Err(__WASI_EINVAL), }; let (output, timespec_out) = unsafe { @@ -58,8 +54,5 @@ pub fn platform_clock_time_get( }; let t_out = (timespec_out.tv_sec * 1_000_000_000).wrapping_add(timespec_out.tv_nsec); - wasi_try_mem!(time.write(t_out as __wasi_timestamp_t)); - - // TODO: map output of clock_gettime to __wasi_errno_t - __WASI_ESUCCESS + Ok(t_out) } diff --git a/lib/wasi/src/syscalls/wasm32.rs b/lib/wasi/src/syscalls/wasm32.rs index 73cadb1b0e6..d9f56ac85c1 100644 --- a/lib/wasi/src/syscalls/wasm32.rs +++ b/lib/wasi/src/syscalls/wasm32.rs @@ -1,25 +1,26 @@ use crate::syscalls::types::*; +use chrono::prelude::*; use std::mem; use wasmer::WasmRef; pub fn platform_clock_res_get( clock_id: __wasi_clockid_t, resolution: WasmRef<__wasi_timestamp_t>, -) -> __wasi_errno_t { - let t_out = 1 * 1_000_000_000; - wasi_try_mem!(resolution.write(t_out as __wasi_timestamp_t)); - - // TODO: map output of clock_getres to __wasi_errno_t - __WASI_ESUCCESS +) -> Result { + let t_out = match clock_id { + __WASI_CLOCK_MONOTONIC => 10_000_000, + __WASI_CLOCK_REALTIME => 1, + __WASI_CLOCK_PROCESS_CPUTIME_ID => 1, + __WASI_CLOCK_THREAD_CPUTIME_ID => 1, + _ => return Err(__WASI_EINVAL), + }; + Ok(t_out) } pub fn platform_clock_time_get( clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, - time: WasmRef<__wasi_timestamp_t>, -) -> __wasi_errno_t { - let t_out = 1 * 1_000_000_000; - wasi_try_mem!(time.write(t_out as __wasi_timestamp_t)); - - __WASI_ESUCCESS +) -> Result { + let new_time: DateTime = Local::now(); + Ok(new_time.timestamp_nanos() as i64) } diff --git a/lib/wasi/src/syscalls/windows.rs b/lib/wasi/src/syscalls/windows.rs index 31fd8f42a1b..c461fa44ca8 100644 --- a/lib/wasi/src/syscalls/windows.rs +++ b/lib/wasi/src/syscalls/windows.rs @@ -5,7 +5,7 @@ use wasmer::WasmRef; pub fn platform_clock_res_get( clock_id: __wasi_clockid_t, resolution: WasmRef<__wasi_timestamp_t>, -) -> __wasi_errno_t { +) -> Result { let resolution_val = match clock_id { // resolution of monotonic clock at 10ms, from: // https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-gettickcount64 @@ -13,34 +13,32 @@ pub fn platform_clock_res_get( // TODO: verify or compute this __WASI_CLOCK_REALTIME => 1, __WASI_CLOCK_PROCESS_CPUTIME_ID => { - return __WASI_EINVAL; + return Err(__WASI_EINVAL); } __WASI_CLOCK_THREAD_CPUTIME_ID => { - return __WASI_EINVAL; + return Err(__WASI_EINVAL); } - _ => return __WASI_EINVAL, + _ => return Err(__WASI_EINVAL), }; - wasi_try_mem!(resolution.write(resolution_val)); - __WASI_ESUCCESS + Ok(resolution_val) } pub fn platform_clock_time_get( clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, - time: WasmRef<__wasi_timestamp_t>, -) -> __wasi_errno_t { +) -> Result { let nanos = match clock_id { __WASI_CLOCK_MONOTONIC => { let tick_ms = unsafe { winapi::um::sysinfoapi::GetTickCount64() }; tick_ms * 1_000_000 } __WASI_CLOCK_REALTIME => { - let duration = wasi_try!(std::time::SystemTime::now() + let duration = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .map_err(|e| { debug!("Error in wasi::platform_clock_time_get: {:?}", e); __WASI_EIO - })); + })?; duration.as_nanos() as u64 } __WASI_CLOCK_PROCESS_CPUTIME_ID => { @@ -49,8 +47,7 @@ pub fn platform_clock_time_get( __WASI_CLOCK_THREAD_CPUTIME_ID => { unimplemented!("wasi::platform_clock_time_get(__WASI_CLOCK_THREAD_CPUTIME_ID, ..)") } - _ => return __WASI_EINVAL, + _ => return Err(__WASI_EINVAL), }; - wasi_try_mem!(time.write(nanos)); - __WASI_ESUCCESS + Ok(nanos as i64) } diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index b46ac0852ba..34a84b4dee7 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -1,5 +1,6 @@ use std::collections::BTreeSet; use wasmer::Module; +use super::types::*; #[allow(dead_code)] /// Check if a provided module is compiled for some version of WASI. @@ -8,6 +9,32 @@ pub fn is_wasi_module(module: &Module) -> bool { get_wasi_version(module, false).is_some() } +pub fn map_io_err(err: std::io::Error) -> __wasi_errno_t { + use std::io::ErrorKind; + match err.kind() { + ErrorKind::NotFound => __WASI_ENOENT, + ErrorKind::PermissionDenied => __WASI_EPERM, + ErrorKind::ConnectionRefused => __WASI_ECONNREFUSED, + ErrorKind::ConnectionReset => __WASI_ECONNRESET, + ErrorKind::ConnectionAborted => __WASI_ECONNABORTED, + ErrorKind::NotConnected => __WASI_ENOTCONN, + ErrorKind::AddrInUse => __WASI_EADDRINUSE, + ErrorKind::AddrNotAvailable => __WASI_EADDRNOTAVAIL, + ErrorKind::BrokenPipe => __WASI_EPIPE, + ErrorKind::AlreadyExists => __WASI_EEXIST, + ErrorKind::WouldBlock => __WASI_EAGAIN, + ErrorKind::InvalidInput => __WASI_EIO, + ErrorKind::InvalidData => __WASI_EIO, + ErrorKind::TimedOut => __WASI_ETIMEDOUT, + ErrorKind::WriteZero => __WASI_EIO, + ErrorKind::Interrupted => __WASI_EINTR, + ErrorKind::Other => __WASI_EIO, + ErrorKind::UnexpectedEof => __WASI_EIO, + ErrorKind::Unsupported => __WASI_ENOTSUP, + _ => __WASI_EIO, + } +} + /// The version of WASI. This is determined by the imports namespace /// string. #[derive(Debug, Clone, Copy, Eq)] diff --git a/lib/wasi/tests/js.rs b/lib/wasi/tests/js.rs index 909e050fde4..fd1c80f831e 100644 --- a/lib/wasi/tests/js.rs +++ b/lib/wasi/tests/js.rs @@ -39,14 +39,15 @@ fn test_stdout() { // Create the `WasiEnv`. // let stdout = Stdout::default(); - let mut wasi_env = WasiState::new("command-name") + let wasi_env = WasiState::new("command-name") .args(&["Gordon"]) // .stdout(Box::new(stdout)) .finalize() .unwrap(); // Generate an `ImportObject`. - let import_object = wasi_env.import_object(&module).unwrap(); + let mut wasi_thread = wasi_env.new_thread(); + let import_object = wasi_thread.import_object(&module).unwrap(); // Let's instantiate the module with the imports. let instance = Instance::new(&module, &import_object).unwrap(); @@ -81,13 +82,14 @@ fn test_env() { .env("TEST", "VALUE") .env("TEST2", "VALUE2"); // panic!("envs: {:?}", wasi_state_builder.envs); - let mut wasi_env = wasi_state_builder + let wasi_env = wasi_state_builder // .stdout(Box::new(stdout)) .finalize() .unwrap(); // Generate an `ImportObject`. - let import_object = wasi_env.import_object(&module).unwrap(); + let mut wasi_thread = wasi_env.new_thread(); + let import_object = wasi_thread.import_object(&module).unwrap(); // Let's instantiate the module with the imports. let instance = Instance::new(&module, &import_object).unwrap(); diff --git a/tests/compilers/config.rs b/tests/compilers/config.rs index 8274ed20044..4cb6fce1adb 100644 --- a/tests/compilers/config.rs +++ b/tests/compilers/config.rs @@ -99,7 +99,7 @@ impl Config { } } - pub fn compiler_config(&self, canonicalize_nans: bool) -> Box { + pub fn compiler_config(&self, #[allow(unused_variables)] canonicalize_nans: bool) -> Box { match &self.compiler { #[cfg(feature = "cranelift")] Compiler::Cranelift => { @@ -135,6 +135,7 @@ impl Config { } } + #[allow(dead_code)] fn add_middlewares(&self, config: &mut dyn CompilerConfig) { for middleware in self.middlewares.iter() { config.push_middleware(middleware.clone()); diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index b01bc70672a..6f4be6fd247 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -1,12 +1,13 @@ use anyhow::Context; use std::fs::{read_dir, File, OpenOptions, ReadDir}; use std::io::{self, Read, Seek, Write}; +use std::sync::{Arc, Mutex, mpsc}; use std::path::{Path, PathBuf}; use wasmer::{Imports, Instance, Module, Store}; use wasmer_vfs::{host_fs, mem_fs, FileSystem}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; use wasmer_wasi::{ - generate_import_object_from_env, get_wasi_version, FsError, Pipe, VirtualFile, WasiEnv, + generate_import_object_from_thread, get_wasi_version, FsError, Pipe, VirtualFile, WasiEnv, WasiState, WasiVersion, }; use wast::parser::{self, Parse, ParseBuffer, Parser}; @@ -39,12 +40,12 @@ pub struct WasiTest<'a> { // TODO: add `test_fs` here to sandbox better const BASE_TEST_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../wasi-wast/wasi/"); -fn get_stdout_output(wasi_state: &WasiState) -> anyhow::Result { - let stdout_boxed = wasi_state.fs.stdout()?.as_ref().unwrap(); - let stdout = (&**stdout_boxed) - .downcast_ref::() - .unwrap(); - let stdout_str = std::str::from_utf8(&stdout.output)?; +fn get_stdio_output(rx: &mpsc::Receiver>) -> anyhow::Result { + let mut stdio = Vec::new(); + while let Ok(mut buf) = rx.try_recv() { + stdio.append(&mut buf); + } + let stdout_str = std::str::from_utf8(&stdio[..])?; #[cfg(target_os = "windows")] // normalize line endings return Ok(stdout_str.replace("\r\n", "\n")); @@ -53,21 +54,6 @@ fn get_stdout_output(wasi_state: &WasiState) -> anyhow::Result { return Ok(stdout_str.to_string()); } -fn get_stderr_output(wasi_state: &WasiState) -> anyhow::Result { - let stderr_boxed = wasi_state.fs.stderr()?.as_ref().unwrap(); - let stderr = (&**stderr_boxed) - .downcast_ref::() - .unwrap(); - let stderr_str = std::str::from_utf8(&stderr.output)?; - - #[cfg(target_os = "windows")] - // normalize line endings - return Ok(stderr_str.replace("\r\n", "\n")); - - #[cfg(not(target_os = "windows"))] - return Ok(stderr_str.to_string()); -} - #[allow(dead_code)] impl<'a> WasiTest<'a> { /// Turn a WASI WAST string into a list of tokens. @@ -95,16 +81,18 @@ impl<'a> WasiTest<'a> { wasm_module.read_to_end(&mut out)?; out }; - let module = Module::new(store, &wasm_bytes)?; - let (env, _tempdirs) = self.create_wasi_env(filesystem_kind)?; + let module = Module::new(&store, &wasm_bytes)?; + let (env, _tempdirs, stdout_rx, stderr_rx) = self.create_wasi_env(filesystem_kind)?; let imports = self.get_imports(store, &module, env.clone())?; let instance = Instance::new(&module, &imports)?; let start = instance.exports.get_function("_start")?; if let Some(stdin) = &self.stdin { - let mut state = env.state(); - let wasi_stdin = state.fs.stdin_mut()?.as_mut().unwrap(); + let state = env.state(); + let inodes = state.inodes.write().unwrap(); + let mut wasi_stdin = inodes.stdin_mut(&state.fs.fd_map)?; + let wasi_stdin = wasi_stdin.as_mut().unwrap(); // Then we can write to it! write!(wasi_stdin, "{}", stdin.stream)?; } @@ -113,9 +101,8 @@ impl<'a> WasiTest<'a> { match start.call(&[]) { Ok(_) => {} Err(e) => { - let wasi_state = env.state(); - let stdout_str = get_stdout_output(&wasi_state)?; - let stderr_str = get_stderr_output(&wasi_state)?; + let stdout_str = get_stdio_output(&stdout_rx)?; + let stderr_str = get_stdio_output(&stderr_rx)?; Err(e).with_context(|| { format!( "failed to run WASI `_start` function: failed with stdout: \"{}\"\nstderr: \"{}\"", @@ -126,15 +113,13 @@ impl<'a> WasiTest<'a> { } } - let wasi_state = env.state(); - if let Some(expected_stdout) = &self.assert_stdout { - let stdout_str = get_stdout_output(&wasi_state)?; + let stdout_str = get_stdio_output(&stdout_rx)?; assert_eq!(stdout_str, expected_stdout.expected); } if let Some(expected_stderr) = &self.assert_stderr { - let stderr_str = get_stderr_output(&wasi_state)?; + let stderr_str = get_stdio_output(&stderr_rx)?; assert_eq!(stderr_str, expected_stderr.expected); } @@ -145,7 +130,7 @@ impl<'a> WasiTest<'a> { fn create_wasi_env( &self, filesystem_kind: WasiFileSystemKind, - ) -> anyhow::Result<(WasiEnv, Vec)> { + ) -> anyhow::Result<(WasiEnv, Vec, mpsc::Receiver>, mpsc::Receiver>)> { let mut builder = WasiState::new(self.wasm_path); let stdin_pipe = Pipe::new(); @@ -216,15 +201,17 @@ impl<'a> WasiTest<'a> { } } + let (stdout, stdout_rx) = OutputCapturerer::new(); + let (stderr, stderr_rx) = OutputCapturerer::new(); let out = builder .args(&self.args) // adding this causes some tests to fail. TODO: investigate this //.env("RUST_BACKTRACE", "1") - .stdout(Box::new(OutputCapturerer::new())) - .stderr(Box::new(OutputCapturerer::new())) + .stdout(Box::new(stdout)) + .stderr(Box::new(stderr)) .finalize()?; - Ok((out, host_temp_dirs_to_not_drop)) + Ok((out, host_temp_dirs_to_not_drop, stdout_rx, stderr_rx)) } /// Get the correct [`WasiVersion`] from the Wasm [`Module`]. @@ -237,8 +224,9 @@ impl<'a> WasiTest<'a> { /// Get the correct WASI import object for the given module and set it up with the /// [`WasiEnv`]. fn get_imports(&self, store: &Store, module: &Module, env: WasiEnv) -> anyhow::Result { + let thread = env.new_thread(); let version = self.get_version(module)?; - Ok(generate_import_object_from_env(store, env, version)) + Ok(generate_import_object_from_thread(store, thread, version)) } } @@ -528,14 +516,15 @@ mod test { } } -#[derive(Debug)] +#[derive(Debug, Clone)] struct OutputCapturerer { - output: Vec, + output: Arc>>>, } impl OutputCapturerer { - fn new() -> Self { - Self { output: vec![] } + fn new() -> (Self, mpsc::Receiver>) { + let (tx, rx) = mpsc::channel(); + (Self { output: Arc::new(Mutex::new(tx)) }, rx) } } @@ -575,18 +564,30 @@ impl Seek for OutputCapturerer { } impl Write for OutputCapturerer { fn write(&mut self, buf: &[u8]) -> io::Result { - self.output.extend_from_slice(buf); + self.output.lock().unwrap().send(buf.to_vec()) + .map_err(|err| io::Error::new( + io::ErrorKind::BrokenPipe, err.to_string(), + ))?; Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.output.extend_from_slice(buf); + self.output.lock().unwrap().send(buf.to_vec()) + .map_err(|err| io::Error::new( + io::ErrorKind::BrokenPipe, err.to_string(), + ))?; Ok(()) } fn write_fmt(&mut self, fmt: std::fmt::Arguments) -> io::Result<()> { - self.output.write_fmt(fmt) + let mut buf = Vec::::new(); + buf.write_fmt(fmt)?; + self.output.lock().unwrap().send(buf) + .map_err(|err| io::Error::new( + io::ErrorKind::BrokenPipe, err.to_string(), + ))?; + Ok(()) } } From 62de9c5aad6c2eaf572d461990fd8dfe7896c8b7 Mon Sep 17 00:00:00 2001 From: Johnathan Sharratt Date: Sat, 14 May 2022 23:58:04 +0200 Subject: [PATCH 2/9] Implemented functionality needed for WASIX and Networking within Web Assembly - Introduced the virtual BUS interface used for RPC between web assembly apps - Introduced the virtual networking interface used to implement networking for web assembly apps - Implemented a local implementation of the virtual networking (available behind the feature toggle 'host-net' on the 'wasi' package) - Fixed up some of the examples from the wasmer3 branch - Refactored the WASI implementations so they support wasm64-wasi - WASIX is behind its own namespaces for both 32bit and 64bit implementations - Fixed the wasi_pipes unit test which was using internals that are no longer exposed - instead made the pipes clonable --- Cargo.lock | 47 + Cargo.toml | 3 + examples/wasi_pipes.rs | 29 +- lib/api/src/js/mem_access.rs | 9 +- lib/api/src/js/ptr.rs | 48 +- lib/api/src/sys/mem_access.rs | 9 +- lib/api/src/sys/ptr.rs | 54 +- lib/c-api/src/wasm_c_api/wasi/mod.rs | 10 + lib/types/src/lib.rs | 3 + lib/types/src/memory.rs | 81 +- lib/vbus/Cargo.toml | 19 + lib/vbus/src/lib.rs | 374 +++ lib/vfs/src/lib.rs | 13 + lib/vnet/Cargo.toml | 20 + lib/vnet/src/lib.rs | 853 ++++++ lib/wasi-local-networking/Cargo.toml | 24 + lib/wasi-local-networking/README.md | 1 + lib/wasi-local-networking/src/lib.rs | 810 ++++++ lib/wasi-types/src/bus.rs | 86 + lib/wasi-types/src/error.rs | 22 + lib/wasi-types/src/file.rs | 147 +- lib/wasi-types/src/io.rs | 52 +- lib/wasi-types/src/lib.rs | 4 + lib/wasi-types/src/net.rs | 494 ++++ lib/wasi-types/src/time.rs | 18 +- lib/wasi/Cargo.toml | 7 +- lib/wasi/src/lib.rs | 309 ++- lib/wasi/src/macros.rs | 8 +- lib/wasi/src/runtime.rs | 158 ++ lib/wasi/src/state/builder.rs | 27 +- lib/wasi/src/state/mod.rs | 103 +- lib/wasi/src/state/pipe.rs | 114 + lib/wasi/src/state/socket.rs | 1387 ++++++++++ lib/wasi/src/state/types.rs | 52 +- lib/wasi/src/syscalls/legacy/snapshot0.rs | 37 +- lib/wasi/src/syscalls/mod.rs | 2849 +++++++++++++++++++-- lib/wasi/src/syscalls/wasi.rs | 405 +++ lib/wasi/src/syscalls/wasix32.rs | 986 +++++++ lib/wasi/src/syscalls/wasix64.rs | 986 +++++++ lib/wasi/src/utils.rs | 86 +- 40 files changed, 10264 insertions(+), 480 deletions(-) create mode 100644 lib/vbus/Cargo.toml create mode 100644 lib/vbus/src/lib.rs create mode 100644 lib/vnet/Cargo.toml create mode 100644 lib/vnet/src/lib.rs create mode 100644 lib/wasi-local-networking/Cargo.toml create mode 100644 lib/wasi-local-networking/README.md create mode 100644 lib/wasi-local-networking/src/lib.rs create mode 100644 lib/wasi-types/src/bus.rs create mode 100644 lib/wasi-types/src/net.rs create mode 100644 lib/wasi/src/runtime.rs create mode 100644 lib/wasi/src/state/pipe.rs create mode 100644 lib/wasi/src/state/socket.rs create mode 100644 lib/wasi/src/syscalls/wasi.rs create mode 100644 lib/wasi/src/syscalls/wasix32.rs create mode 100644 lib/wasi/src/syscalls/wasix64.rs diff --git a/Cargo.lock b/Cargo.lock index 4681497240c..01316b7b11a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,6 +246,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "bytesize" version = "1.1.0" @@ -3179,6 +3185,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "wasmer-vbus" +version = "2.3.0" +dependencies = [ + "libc", + "serde", + "slab", + "thiserror", + "tracing", + "typetag", + "wasmer-vfs", +] + [[package]] name = "wasmer-vfs" version = "2.3.0" @@ -3216,11 +3235,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "wasmer-vnet" +version = "2.3.0" +dependencies = [ + "bytes", + "libc", + "serde", + "slab", + "thiserror", + "tracing", + "typetag", + "wasmer-vfs", +] + [[package]] name = "wasmer-wasi" version = "2.3.0" dependencies = [ "bincode", + "bytes", "cfg-if 1.0.0", "chrono", "derivative", @@ -3235,7 +3269,10 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-test", "wasmer", + "wasmer-vbus", "wasmer-vfs", + "wasmer-vnet", + "wasmer-wasi-local-networking", "wasmer-wasi-types", "winapi", ] @@ -3253,6 +3290,16 @@ dependencies = [ "wasmer-wasi", ] +[[package]] +name = "wasmer-wasi-local-networking" +version = "2.3.0" +dependencies = [ + "bytes", + "tracing", + "wasmer-vfs", + "wasmer-vnet", +] + [[package]] name = "wasmer-wasi-types" version = "2.3.0" diff --git a/Cargo.toml b/Cargo.toml index 12e507d0967..d086b027bb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,10 +47,13 @@ members = [ "lib/engine-staticlib", "lib/object", "lib/vfs", + "lib/vnet", + "lib/vbus", "lib/vm", "lib/wasi", "lib/wasi-types", "lib/wasi-experimental-io-devices", + "lib/wasi-local-networking", "lib/types", "tests/wasi-wast", "tests/lib/wast", diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index 1367a3af255..588a90317d2 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -15,6 +15,7 @@ use wasmer::{Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_universal::Universal; use wasmer_wasi::{Pipe, WasiState}; +use std::io::{Read, Write}; fn main() -> Result<(), Box> { let wasm_path = concat!( @@ -36,11 +37,11 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` with the stdio pipes - let input = Pipe::new(); - let output = Pipe::new(); + let mut input = Pipe::new(); + let mut output = Pipe::new(); let wasi_env = WasiState::new("hello") - .stdin(Box::new(input)) - .stdout(Box::new(output)) + .stdin(Box::new(input.clone())) + .stdout(Box::new(output.clone())) .finalize()?; println!("Instantiating module with WASI imports..."); @@ -52,16 +53,8 @@ fn main() -> Result<(), Box> { let msg = "racecar go zoom"; println!("Writing \"{}\" to the WASI stdin...", msg); - // To write to the stdin, we need a mutable reference to the pipe - // - // We access WasiState in a nested scope to ensure we're not holding - // the mutex after we need it. - { - let mut state = wasi_env.state(); - let wasi_stdin = state.fs.stdin_mut()?.as_mut().unwrap(); - // Then we can write to it! - writeln!(wasi_stdin, "{}", msg)?; - } + // To write to the stdin + writeln!(input, "{}", msg)?; println!("Call WASI `_start` function..."); // And we just call the `_start` function! @@ -69,12 +62,10 @@ fn main() -> Result<(), Box> { start.call(&[])?; println!("Reading from the WASI stdout..."); - // To read from the stdout, we again need a mutable reference to the pipe - let mut state = wasi_env.state(); - let wasi_stdout = state.fs.stdout_mut()?.as_mut().unwrap(); - // Then we can read from it! + + // To read from the stdout let mut buf = String::new(); - wasi_stdout.read_to_string(&mut buf)?; + output.read_to_string(&mut buf)?; println!("Read \"{}\" from the WASI stdout!", buf.trim()); Ok(()) diff --git a/lib/api/src/js/mem_access.rs b/lib/api/src/js/mem_access.rs index 98c98d2a2ba..a865b9ac976 100644 --- a/lib/api/src/js/mem_access.rs +++ b/lib/api/src/js/mem_access.rs @@ -10,7 +10,7 @@ use std::{ string::FromUtf8Error, }; use thiserror::Error; -use wasmer_types::ValueType; +use wasmer_types::{MemorySize, ValueType}; /// Error for invalid [`Memory`] access. #[derive(Clone, Copy, Debug, Error)] @@ -85,6 +85,13 @@ impl<'a, T: ValueType> WasmRef<'a, T> { WasmPtr::new(self.offset) } + /// Get a `WasmPtr` fror this `WasmRef`. + #[inline] + pub fn as_ptr(self) -> WasmPtr { + let offset: M::Offset = self.offset.try_into().map_err(|_| "invalid offset into memory").unwrap(); + WasmPtr::::new(offset) + } + /// Get a reference to the Wasm memory backing this reference. #[inline] pub fn memory(self) -> &'a Memory { diff --git a/lib/api/src/js/ptr.rs b/lib/api/src/js/ptr.rs index c3a4a177724..32fb98da9a0 100644 --- a/lib/api/src/js/ptr.rs +++ b/lib/api/src/js/ptr.rs @@ -4,53 +4,11 @@ use std::convert::TryFrom; use std::{fmt, marker::PhantomData, mem}; use wasmer_types::{NativeWasmType, ValueType}; -/// Trait for the `Memory32` and `Memory64` marker types. -/// -/// This allows code to be generic over 32-bit and 64-bit memories. -pub unsafe trait MemorySize { - /// Type used to represent an offset into a memory. This is `u32` or `u64`. - type Offset: Copy + Into + TryFrom; - - /// Type used to pass this value as an argument or return value for a Wasm function. - type Native: NativeWasmType; - - /// Zero value used for `WasmPtr::is_null`. - const ZERO: Self::Offset; - - /// Convert an `Offset` to a `Native`. - fn offset_to_native(offset: Self::Offset) -> Self::Native; - - /// Convert a `Native` to an `Offset`. - fn native_to_offset(native: Self::Native) -> Self::Offset; -} +pub use wasmer_types::MemorySize; -/// Marker trait for 32-bit memories. -pub struct Memory32; -unsafe impl MemorySize for Memory32 { - type Offset = u32; - type Native = i32; - const ZERO: Self::Offset = 0; - fn offset_to_native(offset: Self::Offset) -> Self::Native { - offset as Self::Native - } - fn native_to_offset(native: Self::Native) -> Self::Offset { - native as Self::Offset - } -} +pub use wasmer_types::Memory32; -/// Marker trait for 64-bit memories. -pub struct Memory64; -unsafe impl MemorySize for Memory64 { - type Offset = u64; - type Native = i64; - const ZERO: Self::Offset = 0; - fn offset_to_native(offset: Self::Offset) -> Self::Native { - offset as Self::Native - } - fn native_to_offset(native: Self::Native) -> Self::Offset { - native as Self::Offset - } -} +pub use wasmer_types::Memory64; /// Alias for `WasmPtr. pub type WasmPtr64 = WasmPtr; diff --git a/lib/api/src/sys/mem_access.rs b/lib/api/src/sys/mem_access.rs index 7a6ba392ebd..74e3849197a 100644 --- a/lib/api/src/sys/mem_access.rs +++ b/lib/api/src/sys/mem_access.rs @@ -1,5 +1,5 @@ use crate::RuntimeError; -use crate::{Memory, Memory32, Memory64, WasmPtr}; +use crate::{Memory, Memory32, Memory64, WasmPtr, MemorySize}; use std::{ convert::TryInto, fmt, @@ -85,6 +85,13 @@ impl<'a, T: ValueType> WasmRef<'a, T> { WasmPtr::new(self.offset) } + /// Get a `WasmPtr` fror this `WasmRef`. + #[inline] + pub fn as_ptr(self) -> WasmPtr { + let offset: M::Offset = self.offset.try_into().map_err(|_| "invalid offset into memory").unwrap(); + WasmPtr::::new(offset) + } + /// Get a reference to the Wasm memory backing this reference. #[inline] pub fn memory(self) -> &'a Memory { diff --git a/lib/api/src/sys/ptr.rs b/lib/api/src/sys/ptr.rs index e52216049c8..3ece04f551e 100644 --- a/lib/api/src/sys/ptr.rs +++ b/lib/api/src/sys/ptr.rs @@ -2,59 +2,13 @@ use crate::sys::{externals::Memory, FromToNativeWasmType}; use crate::{MemoryAccessError, WasmRef, WasmSlice}; use std::convert::TryFrom; use std::{fmt, marker::PhantomData, mem}; -use wasmer_types::{NativeWasmType, ValueType}; +use wasmer_types::ValueType; -/// Trait for the `Memory32` and `Memory64` marker types. -/// -/// This allows code to be generic over 32-bit and 64-bit memories. -/// -/// # Safety -/// -/// Used for raw memory access. -pub unsafe trait MemorySize { - /// Type used to represent an offset into a memory. This is `u32` or `u64`. - type Offset: Copy + Into + TryFrom; - - /// Type used to pass this value as an argument or return value for a Wasm function. - type Native: NativeWasmType; - - /// Zero value used for `WasmPtr::is_null`. - const ZERO: Self::Offset; - - /// Convert an `Offset` to a `Native`. - fn offset_to_native(offset: Self::Offset) -> Self::Native; - - /// Convert a `Native` to an `Offset`. - fn native_to_offset(native: Self::Native) -> Self::Offset; -} +pub use wasmer_types::MemorySize; -/// Marker trait for 32-bit memories. -pub struct Memory32; -unsafe impl MemorySize for Memory32 { - type Offset = u32; - type Native = i32; - const ZERO: Self::Offset = 0; - fn offset_to_native(offset: Self::Offset) -> Self::Native { - offset as Self::Native - } - fn native_to_offset(native: Self::Native) -> Self::Offset { - native as Self::Offset - } -} +pub use wasmer_types::Memory32; -/// Marker trait for 64-bit memories. -pub struct Memory64; -unsafe impl MemorySize for Memory64 { - type Offset = u64; - type Native = i64; - const ZERO: Self::Offset = 0; - fn offset_to_native(offset: Self::Offset) -> Self::Native { - offset as Self::Native - } - fn native_to_offset(native: Self::Native) -> Self::Offset { - native as Self::Offset - } -} +pub use wasmer_types::Memory64; /// Alias for `WasmPtr. pub type WasmPtr64 = WasmPtr; diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index b1146b82a28..11e2f800207 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -287,6 +287,12 @@ pub enum wasi_version_t { /// `wasi_snapshot_preview1`. SNAPSHOT1 = 2, + + /// `wasix_32v1`. + WASIX32V1 = 3, + + /// `wasix_64v1`. + WASIX64V1 = 4, } impl From for wasi_version_t { @@ -294,6 +300,8 @@ impl From for wasi_version_t { match other { WasiVersion::Snapshot0 => wasi_version_t::SNAPSHOT0, WasiVersion::Snapshot1 => wasi_version_t::SNAPSHOT1, + WasiVersion::Wasix32v1 => wasi_version_t::WASIX32V1, + WasiVersion::Wasix64v1 => wasi_version_t::WASIX64V1, WasiVersion::Latest => wasi_version_t::LATEST, } } @@ -307,6 +315,8 @@ impl TryFrom for WasiVersion { wasi_version_t::INVALID_VERSION => return Err("Invalid WASI version cannot be used"), wasi_version_t::SNAPSHOT0 => WasiVersion::Snapshot0, wasi_version_t::SNAPSHOT1 => WasiVersion::Snapshot1, + wasi_version_t::WASIX32V1 => WasiVersion::Wasix32v1, + wasi_version_t::WASIX64V1 => WasiVersion::Wasix64v1, wasi_version_t::LATEST => WasiVersion::Latest, }) } diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index da421966b15..01ac5c64840 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -93,6 +93,9 @@ pub use types::{ ExportType, ExternType, FunctionType, GlobalInit, GlobalType, ImportType, MemoryType, Mutability, TableType, Type, V128, }; +pub use crate::memory::{ + MemorySize, Memory32, Memory64 +}; #[cfg(feature = "enable-rkyv")] pub use archives::ArchivableIndexMap; diff --git a/lib/types/src/memory.rs b/lib/types/src/memory.rs index 6c459cbb8c3..560dad9bf7d 100644 --- a/lib/types/src/memory.rs +++ b/lib/types/src/memory.rs @@ -1,8 +1,11 @@ -use crate::Pages; +use crate::{Pages, ValueType}; #[cfg(feature = "enable-rkyv")] use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; +use std::convert::{TryFrom, TryInto}; +use std::iter::Sum; +use std::ops::{Add, AddAssign}; /// Implementation styles for WebAssembly linear memory. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -43,3 +46,79 @@ impl MemoryStyle { } } } + +/// Trait for the `Memory32` and `Memory64` marker types. +/// +/// This allows code to be generic over 32-bit and 64-bit memories. +pub unsafe trait MemorySize: Copy { + /// Type used to represent an offset into a memory. This is `u32` or `u64`. + type Offset: Default + + std::fmt::Debug + + std::fmt::Display + + Eq + + Ord + + PartialEq + + PartialOrd + + Clone + + Copy + + ValueType + + Into + + From + + From + + From + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryInto + + TryInto + + TryInto + + TryInto + + TryInto + + TryFrom + + Add + + Sum + + AddAssign; + + /// Type used to pass this value as an argument or return value for a Wasm function. + type Native: super::NativeWasmType; + + /// Zero value used for `WasmPtr::is_null`. + const ZERO: Self::Offset; + + /// Convert an `Offset` to a `Native`. + fn offset_to_native(offset: Self::Offset) -> Self::Native; + + /// Convert a `Native` to an `Offset`. + fn native_to_offset(native: Self::Native) -> Self::Offset; +} + +/// Marker trait for 32-bit memories. +#[derive(Clone, Copy)] +pub struct Memory32; +unsafe impl MemorySize for Memory32 { + type Offset = u32; + type Native = i32; + const ZERO: Self::Offset = 0; + fn offset_to_native(offset: Self::Offset) -> Self::Native { + offset as Self::Native + } + fn native_to_offset(native: Self::Native) -> Self::Offset { + native as Self::Offset + } +} + +/// Marker trait for 64-bit memories. +#[derive(Clone, Copy)] +pub struct Memory64; +unsafe impl MemorySize for Memory64 { + type Offset = u64; + type Native = i64; + const ZERO: Self::Offset = 0; + fn offset_to_native(offset: Self::Offset) -> Self::Native { + offset as Self::Native + } + fn native_to_offset(native: Self::Native) -> Self::Offset { + native as Self::Offset + } +} diff --git a/lib/vbus/Cargo.toml b/lib/vbus/Cargo.toml new file mode 100644 index 00000000000..bf0400e2290 --- /dev/null +++ b/lib/vbus/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "wasmer-vbus" +version = "2.3.0" +description = "Wasmer Virtual Bus" +authors = ["Wasmer Engineering Team "] +license = "MIT" +edition = "2018" + +[dependencies] +libc = { version = "^0.2", default-features = false, optional = true } +thiserror = "1" +tracing = { version = "0.1" } +typetag = { version = "0.1", optional = true } +serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +slab = { version = "0.4", optional = true } +wasmer-vfs = { path = "../vfs", version = "=2.3.0", default-features = false } + +[features] +default = [] diff --git a/lib/vbus/src/lib.rs b/lib/vbus/src/lib.rs new file mode 100644 index 00000000000..b949fc84d7c --- /dev/null +++ b/lib/vbus/src/lib.rs @@ -0,0 +1,374 @@ +use std::fmt; +use std::pin::Pin; +use std::task::{Context, Poll}; +use thiserror::Error; + +pub use wasmer_vfs::StdioMode; +pub use wasmer_vfs::FileDescriptor; + +pub type Result = std::result::Result; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct BusDescriptor(usize); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct CallDescriptor(usize); + +pub trait VirtualBus: fmt::Debug + Send + Sync + 'static +{ + /// Starts a new WAPM sub process + fn new_spawn( + &self, + ) -> SpawnOptions; + + /// Creates a listener thats used to receive BUS commands + fn listen( + &self + )-> Result>; +} + +pub trait VirtualBusSpawner { + /// Spawns a new WAPM process by its name + fn spawn(&mut self, name: &str, config: &SpawnOptionsConfig) -> Result; +} + +#[derive(Debug, Clone)] +pub struct SpawnOptionsConfig { + chroot: bool, + args: Vec, + preopen: Vec, + stdin_mode: StdioMode, + stdout_mode: StdioMode, + stderr_mode: StdioMode, + working_dir: String, + remote_instance: Option, + access_token: Option, +} + +impl SpawnOptionsConfig { + pub const fn chroot(&self) -> bool { + self.chroot + } + + pub const fn args(&self) -> &Vec { + &self.args + } + + pub const fn preopen(&self) -> &Vec { + &self.preopen + } + + pub const fn stdin_mode(&self) -> StdioMode { + self.stdin_mode + } + + pub const fn stdout_mode(&self) -> StdioMode { + self.stdout_mode + } + + pub const fn stderr_mode(&self) -> StdioMode { + self.stderr_mode + } + + pub fn working_dir(&self) -> &str { + self.working_dir.as_str() + } + + pub fn remote_instance(&self) -> Option<&str> { + self.remote_instance.as_ref().map(|a| a.as_str()) + } + + pub fn access_token(&self) -> Option<&str> { + self.access_token.as_ref().map(|a| a.as_str()) + } +} + +pub struct SpawnOptions { + spawner: Box, + conf: SpawnOptionsConfig, +} + +impl SpawnOptions { + pub fn new(spawner: Box) -> Self { + Self { + spawner, + conf: SpawnOptionsConfig { + chroot: false, + args: Vec::new(), + preopen: Vec::new(), + stdin_mode: StdioMode::Null, + stdout_mode: StdioMode::Null, + stderr_mode: StdioMode::Null, + working_dir: "/".to_string(), + remote_instance: None, + access_token: None, + }, + } + } + pub fn options(&mut self, options: SpawnOptionsConfig) -> &mut Self { + self.conf = options; + self + } + + pub fn args(&mut self, args: Vec) -> &mut Self { + self.conf.args = args; + self + } + + pub fn preopen(&mut self, preopen: Vec) -> &mut Self { + self.conf.preopen = preopen; + self + } + + pub fn stdin_mode(&mut self, stdin_mode: StdioMode) -> &mut Self { + self.conf.stdin_mode = stdin_mode; + self + } + + pub fn stdout_mode(&mut self, stdout_mode: StdioMode) -> &mut Self { + self.conf.stdout_mode = stdout_mode; + self + } + + pub fn stderr_mode(&mut self, stderr_mode: StdioMode) -> &mut Self { + self.conf.stderr_mode = stderr_mode; + self + } + + pub fn working_dir(&mut self, working_dir: String) -> &mut Self { + self.conf.working_dir = working_dir; + self + } + + pub fn remote_instance(&mut self, remote_instance: String) -> &mut Self { + self.conf.remote_instance = Some(remote_instance); + self + } + + pub fn access_token(&mut self, access_token: String) -> &mut Self { + self.conf.access_token = Some(access_token); + self + } + + /// Spawns a new bus instance by its reference name + pub fn spawn(&mut self, name: &str) -> Result { + self.spawner.spawn(name, &self.conf) + } +} + +#[derive(Debug)] +pub struct BusSpawnedProcess +{ + /// Handle of the instance + pub handle: BusDescriptor, + /// Reference to the spawned instance + pub inst: Box, +} + +pub trait VirtualBusScope: fmt::Debug + Send + Sync + 'static +{ + //// Returns true if the invokable target has finished + fn poll_finished( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<()>; +} + +pub trait VirtualBusInvokable: fmt::Debug + Send + Sync + 'static +{ + /// Invokes a service within this instance + fn invoke( + &self, + topic: String, + format: BusDataFormat, + buf: &[u8] + ) -> Result>; +} + +pub trait VirtualBusProcess: VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static +{ + /// Returns the exit code if the instance has finished + fn exit_code( + &self, + ) -> Option; + + /// Returns a file descriptor used to read the STDIN + fn stdin_fd(&self) -> Option; + + /// Returns a file descriptor used to write to STDOUT + fn stdout_fd(&self) -> Option; + + /// Returns a file descriptor used to write to STDERR + fn stderr_fd(&self) -> Option; +} + +pub trait VirtualBusInvocation: VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static +{ + /// Polls for new listen events related to this context + fn poll_event( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll; +} + +#[derive(Debug)] +pub enum BusInvocationEvent +{ + /// The server has sent some out-of-band data to you + Callback { + /// Topic that this call relates to + topic: String, + /// Format of the data we received + format: BusDataFormat, + /// Data passed in the call + data: Vec, + }, + /// The service has a responded to your call + Response { + /// Format of the data we received + format: BusDataFormat, + /// Data returned by the call + data: Vec, + }, +} + +pub trait VirtualBusListener: fmt::Debug + Send + Sync + 'static +{ + /// Polls for new calls to this service + fn poll_call( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll; +} + +#[derive(Debug)] +pub struct BusCallEvent +{ + /// Topic that this call relates to + pub topic: String, + /// Reference to the call itself + pub called: Box, + /// Format of the data we received + pub format: BusDataFormat, + /// Data passed in the call + pub data: Vec, +} + +pub trait VirtualBusCalled: VirtualBusListener + fmt::Debug + Send + Sync + 'static +{ + /// Sends an out-of-band message back to the caller + fn callback( + &self, + topic: String, + format: BusDataFormat, + buf: &[u8], + ) -> Result<()>; + + /// Informs the caller that their call has failed + fn fault( + self, + fault: BusError, + ) -> Result<()>; + + /// Finishes the call and returns a particular response + fn reply( + self, + format: BusDataFormat, + buf: &[u8], + ) -> Result<()>; +} + +/// Format that the supplied data is in +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum BusDataFormat { + Raw, + Bincode, + MessagePack, + Json, + Yaml, + Xml, +} + +#[derive(Debug, Default)] +pub struct UnsupportedVirtualBus { } + +impl VirtualBus +for UnsupportedVirtualBus { + fn new_spawn(&self) -> SpawnOptions { + SpawnOptions::new(Box::new(UnsupportedVirtualBusSpawner::default())) + } + + fn listen(&self) -> Result> { + Err(BusError::Unsupported) + } +} + +#[derive(Debug, Default)] +pub struct UnsupportedVirtualBusSpawner { } + +impl VirtualBusSpawner +for UnsupportedVirtualBusSpawner { + fn spawn(&mut self, _name: &str, _config: &SpawnOptionsConfig) -> Result { + Err(BusError::Unsupported) + } +} + +#[derive(Error, Copy, Clone, Debug, PartialEq, Eq)] +pub enum BusError { + /// Failed during serialization + #[error("serialization failed")] + Serialization, + /// Failed during deserialization + #[error("deserialization failed")] + Deserialization, + /// Invalid WAPM process + #[error("invalid wapm")] + InvalidWapm, + /// Failed to fetch the WAPM process + #[error("fetch failed")] + FetchFailed, + /// Failed to compile the WAPM process + #[error("compile error")] + CompileError, + /// Invalid ABI + #[error("WAPM process has an invalid ABI")] + InvalidABI, + /// Call was aborted + #[error("call aborted")] + Aborted, + /// Bad handle + #[error("bad handle")] + BadHandle, + /// Invalid topic + #[error("invalid topic")] + InvalidTopic, + /// Invalid callback + #[error("invalid callback")] + BadCallback, + /// Call is unsupported + #[error("unsupported")] + Unsupported, + /// Bad request + #[error("bad request")] + BadRequest, + /// Access denied + #[error("access denied")] + AccessDenied, + /// Internal error has occured + #[error("internal error")] + InternalError, + /// Memory allocation failed + #[error("memory allocation failed")] + MemoryAllocationFailed, + /// Invocation has failed + #[error("invocation has failed")] + InvokeFailed, + /// Memory access violation + #[error("memory access violation")] + MemoryAccessViolation, + /// Some other unhandled error. If you see this, it's probably a bug. + #[error("unknown error found")] + UnknownError, +} diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index ccb49bf944b..c74132d6e08 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -245,6 +245,19 @@ impl dyn VirtualFile + 'static { } } +/// Determines the mode that stdio handlers will operate in +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum StdioMode { + /// Stdio will be piped to a file descriptor + Piped, + /// Stdio will inherit the file handlers of its parent + Inherit, + /// Stdio will be dropped + Null, + /// Stdio will be sent to the log handler + Log, +} + /// Error type for external users #[derive(Error, Copy, Clone, Debug, PartialEq, Eq)] pub enum FsError { diff --git a/lib/vnet/Cargo.toml b/lib/vnet/Cargo.toml new file mode 100644 index 00000000000..a61e8175282 --- /dev/null +++ b/lib/vnet/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "wasmer-vnet" +version = "2.3.0" +description = "Wasmer Virtual Networking" +authors = ["Wasmer Engineering Team "] +license = "MIT" +edition = "2018" + +[dependencies] +libc = { version = "^0.2", default-features = false, optional = true } +thiserror = "1" +tracing = { version = "0.1" } +typetag = { version = "0.1", optional = true } +serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +slab = { version = "0.4", optional = true } +wasmer-vfs = { path = "../vfs", version = "=2.3.0", default-features = false } +bytes = "1" + +[features] +default = [] diff --git a/lib/vnet/src/lib.rs b/lib/vnet/src/lib.rs new file mode 100644 index 00000000000..cd33c448a8c --- /dev/null +++ b/lib/vnet/src/lib.rs @@ -0,0 +1,853 @@ +use std::fmt; +use std::net::IpAddr; +use std::net::Ipv4Addr; +use std::net::Ipv6Addr; +use std::net::SocketAddr; +use std::net::Shutdown; +use std::sync::Arc; +use std::sync::Mutex; +use std::time::Duration; +use std::sync::mpsc; +use thiserror::Error; + +pub use bytes::Bytes; +pub use bytes::BytesMut; + +pub type Result = std::result::Result; + +/// Socket descriptors are also file descriptors and so +/// all file operations can also be used on sockets +pub type SocketDescriptor = wasmer_vfs::FileDescriptor; + +/// Represents an IP address and its netmask +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct IpCidr +{ + pub ip: IpAddr, + pub prefix: u8, +} + +/// Represents a routing entry in the routing table of the interface +#[derive(Clone, Debug)] +pub struct IpRoute +{ + pub cidr: IpCidr, + pub via_router: IpAddr, + pub preferred_until: Option, + pub expires_at: Option +} + +/// An implementation of virtual networking +pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static +{ + /// Establishes a web socket connection + /// (note: this does not use the virtual sockets and is standalone + /// functionality that works without the network being connected) + fn ws_connect( + &self, + url: &str, + ) -> Result>; + + /// Makes a HTTP request to a remote web resource + /// The headers are separated by line breaks + /// (note: this does not use the virtual sockets and is standalone + /// functionality that works without the network being connected) + fn http_request( + &self, + url: &str, + method: &str, + headers: &str, + gzip: bool, + ) -> Result; + + /// Bridges this local network with a remote network, which is required in + /// order to make lower level networking calls (such as UDP/TCP) + fn bridge( + &self, + network: &str, + access_token: &str, + security: StreamSecurity, + ) -> Result<()>; + + /// Disconnects from the remote network essentially unbridging it + fn unbridge( + &self, + ) -> Result<()>; + + /// Acquires an IP address on the network and configures the routing tables + fn dhcp_acquire( + &self, + ) -> Result>; + + /// Adds a static IP address to the interface with a netmask prefix + fn ip_add( + &self, + ip: IpAddr, + prefix: u8, + ) -> Result<()>; + + /// Removes a static (or dynamic) IP address from the interface + fn ip_remove( + &self, + ip: IpAddr, + ) -> Result<()>; + + /// Clears all the assigned IP addresses for this interface + fn ip_clear( + &self, + ) -> Result<()>; + + /// Lists all the IP addresses currently assigned to this interface + fn ip_list( + &self, + ) -> Result>; + + /// Returns the hardware MAC address for this interface + fn mac( + &self, + ) -> Result<[u8; 6]>; + + /// Adds a default gateway to the routing table + fn gateway_set( + &self, + ip: IpAddr, + ) -> Result<()>; + + /// Adds a specific route to the routing table + fn route_add( + &self, + cidr: IpCidr, + via_router: IpAddr, + preferred_until: Option, + expires_at: Option, + ) -> Result<()>; + + /// Removes a routing rule from the routing table + fn route_remove( + &self, + cidr: IpAddr, + ) -> Result<()>; + + /// Clears the routing table for this interface + fn route_clear( + &self, + ) -> Result<()>; + + /// Lists all the routes defined in the routing table for this interface + fn route_list( + &self, + ) -> Result>; + + /// Creates a low level socket that can read and write Ethernet packets + /// directly to the interface + fn bind_raw( + &self, + ) -> Result>; + + /// Lists for TCP connections on a specific IP and Port combination + /// Multiple servers (processes or threads) can bind to the same port if they each set + /// the reuse-port and-or reuse-addr flags + fn listen_tcp( + &self, + addr: SocketAddr, + only_v6: bool, + reuse_port: bool, + reuse_addr: bool, + ) -> Result>; + + /// Opens a UDP socket that listens on a specific IP and Port combination + /// Multiple servers (processes or threads) can bind to the same port if they each set + /// the reuse-port and-or reuse-addr flags + fn bind_udp( + &self, + addr: SocketAddr, + reuse_port: bool, + reuse_addr: bool, + ) -> Result>; + + /// Creates a socket that can be used to send and receive ICMP packets + /// from a paritcular IP address + fn bind_icmp( + &self, + addr: IpAddr, + ) -> Result>; + + /// Opens a TCP connection to a particular destination IP address and port + fn connect_tcp( + &self, + addr: SocketAddr, + peer: SocketAddr, + timeout: Option, + ) -> Result>; + + /// Performs DNS resolution for a specific hostname + fn resolve( + &self, + host: &str, + port: Option, + dns_server: Option, + ) -> Result>; +} + +/// Holds the interface used to work with a pending HTTP request +#[derive(Debug)] +pub struct SocketHttpRequest +{ + /// Used to send the request bytes to the HTTP server + /// (once all bytes are send the sender should be closed) + pub request: Option>>, + /// Used to receive the response bytes from the HTTP server + /// (once all the bytes have been received the receiver will be closed) + pub response: Option>>, + /// Used to receive all the headers from the HTTP server + /// (once all the headers have been received the receiver will be closed) + pub headers: Option>, + /// Used to watch for the status + pub status: Arc>>>, +} + +/// Represents the final result of a HTTP request +#[derive(Debug)] +pub struct HttpStatus +{ + /// Indicates if the HTTP request was redirected to another URL / server + pub redirected: bool, + /// Size of the data held in the response receiver + pub size: usize, + /// Status code returned by the server + pub status: u16, + /// Status text returned by the server + pub status_text: String, +} + +#[derive(Debug)] +pub struct SocketReceive +{ + /// Data that was received + pub data: Bytes, + /// Indicates if the data was truncated (e.g. UDP packet) + pub truncated: bool, +} + +#[derive(Debug)] +pub struct SocketReceiveFrom +{ + /// Data that was received + pub data: Bytes, + /// Indicates if the data was truncated (e.g. UDP packet) + pub truncated: bool, + /// Peer sender address of the data + pub addr: SocketAddr +} + +pub trait VirtualTcpListener: fmt::Debug + Send + Sync + 'static +{ + /// Accepts an connection attempt that was made to this listener + fn accept( + &self, + ) -> Result<(Box, SocketAddr)>; + + /// Accepts an connection attempt that was made to this listener (or times out) + fn accept_timeout( + &self, + timeout: Duration + ) -> Result<(Box, SocketAddr)>; + + /// Sets the accept timeout + fn set_timeout( + &mut self, + timeout: Option + ) -> Result<()>; + + /// Gets the accept timeout + fn timeout( + &self + ) -> Result>; + + /// Returns the local address of this TCP listener + fn addr_local( + &self, + ) -> Result; + + /// Sets how many network hops the packets are permitted for new connections + fn set_ttl( + &mut self, + ttl: u8, + ) -> Result<()>; + + /// Returns the maximum number of network hops before packets are dropped + fn ttl( + &self, + ) -> Result; +} + +pub trait VirtualSocket: fmt::Debug + Send + Sync + 'static +{ + /// Sets how many network hops the packets are permitted for new connections + fn set_ttl( + &mut self, + ttl: u32, + ) -> Result<()>; + + /// Returns the maximum number of network hops before packets are dropped + fn ttl( + &self, + ) -> Result; + + /// Returns the local address for this socket + fn addr_local( + &self, + ) -> Result; + + /// Returns the status/state of the socket + fn status( + &self, + ) -> Result; +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum SocketStatus +{ + Opening, + Opened, + Closed, + Failed +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum StreamSecurity +{ + Unencrypted, + AnyEncyption, + ClassicEncryption, + DoubleEncryption, +} + +/// Interface used for sending and receiving data from a web socket +pub trait VirtualWebSocket: fmt::Debug + Send + Sync + 'static +{ + /// Sends out a datagram or stream of bytes on this socket + fn send( + &mut self, + data: Bytes, + ) -> Result; + + /// FLushes all the datagrams + fn flush( + &mut self, + ) -> Result<()>; + + /// Recv a packet from the socket + fn recv( + &mut self, + ) -> Result; +} + +/// Connected sockets have a persistent connection to a remote peer +pub trait VirtualConnectedSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static +{ + /// Determines how long the socket will remain in a TIME_WAIT + /// after it disconnects (only the one that initiates the close will + /// be in a TIME_WAIT state thus the clients should always do this rather + /// than the server) + fn set_linger( + &mut self, + linger: Option, + ) -> Result<()>; + + /// Returns how long the socket will remain in a TIME_WAIT + /// after it disconnects + fn linger( + &self, + ) -> Result>; + + /// Sends out a datagram or stream of bytes on this socket + fn send( + &mut self, + data: Bytes, + ) -> Result; + + /// FLushes all the datagrams + fn flush( + &mut self, + ) -> Result<()>; + + /// Recv a packet from the socket + fn recv( + &mut self, + ) -> Result; + + /// Peeks for a packet from the socket + fn peek( + &mut self, + ) -> Result; +} + +/// Connectionless sockets are able to send and receive datagrams and stream +/// bytes to multiple addresses at the same time (peer-to-peer) +pub trait VirtualConnectionlessSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static +{ + /// Sends out a datagram or stream of bytes on this socket + /// to a specific address + fn send_to( + &mut self, + data: Bytes, + addr: SocketAddr, + ) -> Result; + + /// Recv a packet from the socket + fn recv_from( + &mut self, + ) -> Result; + + /// Peeks for a packet from the socket + fn peek_from( + &mut self, + ) -> Result; +} + +/// ICMP sockets are low level devices bound to a specific address +/// that can send and receive ICMP packets +pub trait VirtualIcmpSocket: VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static +{ +} + +pub trait VirtualRawSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static +{ + /// Sends out a raw packet on this socket + fn send( + &mut self, + data: Bytes, + ) -> Result; + + /// FLushes all the datagrams + fn flush( + &mut self, + ) -> Result<()>; + + /// Recv a packet from the socket + fn recv( + &mut self, + ) -> Result; + + /// Tells the raw socket and its backing switch that all packets + /// should be received by this socket even if they are not + /// destined for this device + fn set_promiscuous( + &mut self, + promiscuous: bool + ) -> Result<()>; + + /// Returns if the socket is running in promiscuous mode whereby it + /// will receive all packets even if they are not destined for the + /// local interface + fn promiscuous( + &self, + ) -> Result; +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum TimeType +{ + ReadTimeout, + WriteTimeout, + AcceptTimeout, + ConnectTimeout, + Linger, +} + +pub trait VirtualTcpSocket: VirtualConnectedSocket + fmt::Debug + Send + Sync + 'static +{ + /// Sets the timeout for a specific action on the socket + fn set_opt_time( + &mut self, + ty: TimeType, + timeout: Option, + ) -> Result<()>; + + /// Returns one of the previous set timeouts + fn opt_time( + &self, + ty: TimeType, + ) -> Result>; + + /// Sets the receive buffer size which acts as a trottle for how + /// much data is buffered on this side of the pipe + fn set_recv_buf_size( + &mut self, + size: usize, + ) -> Result<()>; + + /// Size of the receive buffer that holds all data that has not + /// yet been read + fn recv_buf_size( + &self, + ) -> Result; + + /// Sets the size of the send buffer which will hold the bytes of + /// data while they are being sent over to the peer + fn set_send_buf_size( + &mut self, + size: usize, + ) -> Result<()>; + + /// Size of the send buffer that holds all data that is currently + /// being transmitted. + fn send_buf_size( + &self, + ) -> Result; + + /// When NO_DELAY is set the data that needs to be transmitted to + /// the peer is sent immediately rather than waiting for a bigger + /// batch of data, this reduces latency but increases encapsulation + /// overhead. + fn set_nodelay( + &mut self, + reuse: bool + ) -> Result<()>; + + /// Indicates if the NO_DELAY flag is set which means that data + /// is immediately sent to the peer without waiting. This reduces + /// latency but increases encapsulation overhead. + fn nodelay( + &self, + ) -> Result; + + /// Returns the address (IP and Port) of the peer socket that this + /// is conencted to + fn addr_peer( + &self, + ) -> Result; + + /// Causes all the data held in the send buffer to be immediately + /// flushed to the destination peer + fn flush( + &mut self, + ) -> Result<()>; + + /// Shuts down either the READER or WRITER sides of the socket + /// connection. + fn shutdown( + &mut self, + how: Shutdown, + ) -> Result<()>; +} + +pub trait VirtualUdpSocket: VirtualConnectedSocket + VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static +{ + /// Connects to a destination peer so that the normal + /// send/recv operations can be used. + fn connect( + &mut self, + addr: SocketAddr, + ) -> Result<()>; + + /// Sets a flag that means that the UDP socket is able + /// to receive and process broadcast packets. + fn set_broadcast( + &mut self, + broadcast: bool + ) -> Result<()>; + + /// Indicates if the SO_BROADCAST flag is set which means + /// that the UDP socket will receive and process broadcast + /// packets + fn broadcast( + &self, + ) -> Result; + + /// Sets a flag that indicates if multicast packets that + /// this socket is a member of will be looped back to + /// the sending socket. This applies to IPv4 addresses + fn set_multicast_loop_v4( + &mut self, + val: bool + ) -> Result<()>; + + /// Gets a flag that indicates if multicast packets that + /// this socket is a member of will be looped back to + /// the sending socket. This applies to IPv4 addresses + fn multicast_loop_v4( + &self, + ) -> Result; + + /// Sets a flag that indicates if multicast packets that + /// this socket is a member of will be looped back to + /// the sending socket. This applies to IPv6 addresses + fn set_multicast_loop_v6( + &mut self, + val: bool + ) -> Result<()>; + + /// Gets a flag that indicates if multicast packets that + /// this socket is a member of will be looped back to + /// the sending socket. This applies to IPv6 addresses + fn multicast_loop_v6( + &self, + ) -> Result; + + /// Sets the TTL for IPv4 multicast packets which is the + /// number of network hops before the packet is dropped + fn set_multicast_ttl_v4( + &mut self, + ttl: u32, + ) -> Result<()>; + + /// Gets the TTL for IPv4 multicast packets which is the + /// number of network hops before the packet is dropped + fn multicast_ttl_v4( + &self, + ) -> Result; + + /// Tells this interface that it will subscribe to a + /// particular multicast address. This applies to IPv4 addresses + fn join_multicast_v4( + &mut self, + multiaddr: Ipv4Addr, + iface: Ipv4Addr, + ) -> Result<()>; + + /// Tells this interface that it will unsubscribe to a + /// particular multicast address. This applies to IPv4 addresses + fn leave_multicast_v4( + &mut self, + multiaddr: Ipv4Addr, + iface: Ipv4Addr, + ) -> Result<()>; + + /// Tells this interface that it will subscribe to a + /// particular multicast address. This applies to IPv6 addresses + fn join_multicast_v6( + &mut self, + multiaddr: Ipv6Addr, + iface: u32, + ) -> Result<()>; + + /// Tells this interface that it will unsubscribe to a + /// particular multicast address. This applies to IPv6 addresses + fn leave_multicast_v6( + &mut self, + multiaddr: Ipv6Addr, + iface: u32, + ) -> Result<()>; + + /// Returns the remote address of this UDP socket if it has been + /// connected to a specific target destination address + fn addr_peer( + &self, + ) -> Result>; +} + +#[derive(Debug, Default)] +pub struct UnsupportedVirtualNetworking { } + +impl VirtualNetworking +for UnsupportedVirtualNetworking +{ + fn ws_connect(&self, _url: &str) -> Result> { + Err(NetworkError::Unsupported) + } + + fn http_request(&self, _url: &str, _method: &str, _headers: &str, _gzip: bool) -> Result { + Err(NetworkError::Unsupported) + } + + fn bridge(&self, _network: &str, _access_token: &str, _security: StreamSecurity) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn unbridge(&self) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn dhcp_acquire(&self) -> Result> { + Err(NetworkError::Unsupported) + } + + fn ip_add(&self, _ip: IpAddr, _prefix: u8) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn ip_remove(&self, _ip: IpAddr) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn ip_clear(&self) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn ip_list(&self) -> Result> { + Err(NetworkError::Unsupported) + } + + fn mac(&self) -> Result<[u8; 6]> { + Err(NetworkError::Unsupported) + } + + fn gateway_set(&self, _ip: IpAddr) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn route_add(&self, _cidr: IpCidr, _via_router: IpAddr, _preferred_until: Option, _expires_at: Option) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn route_remove(&self, _cidr: IpAddr) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn route_clear(&self) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn route_list(&self) -> Result> { + Err(NetworkError::Unsupported) + } + + fn bind_raw(&self) -> Result> { + Err(NetworkError::Unsupported) + } + + fn bind_icmp(&self, _addr: IpAddr) -> Result> { + Err(NetworkError::Unsupported) + } + + fn listen_tcp(&self, _addr: SocketAddr, _only_v6: bool, _reuse_port: bool, _reuse_addr: bool) -> Result> { + Err(NetworkError::Unsupported) + } + + fn connect_tcp(&self, _addr: SocketAddr, _peer: SocketAddr, _timeout: Option) -> Result> { + Err(NetworkError::Unsupported) + } + + fn bind_udp(&self, _addr: SocketAddr, _reuse_port: bool, _reuse_addr: bool) -> Result> { + Err(NetworkError::Unsupported) + } + + fn resolve(&self, _host: &str, _port: Option, _dns_server: Option) -> Result> { + Err(NetworkError::Unsupported) + } +} + +#[derive(Error, Copy, Clone, Debug, PartialEq, Eq)] +pub enum NetworkError { + /// The handle given was not usable + #[error("invalid fd")] + InvalidFd, + /// File exists + #[error("file exists")] + AlreadyExists, + /// The filesystem has failed to lock a resource. + #[error("lock error")] + Lock, + /// Something failed when doing IO. These errors can generally not be handled. + /// It may work if tried again. + #[error("io error")] + IOError, + /// The address was in use + #[error("address is in use")] + AddressInUse, + /// The address could not be found + #[error("address could not be found")] + AddressNotAvailable, + /// A pipe was closed + #[error("broken pipe (was closed)")] + BrokenPipe, + /// The connection was aborted + #[error("connection aborted")] + ConnectionAborted, + /// The connection request was refused + #[error("connection refused")] + ConnectionRefused, + /// The connection was reset + #[error("connection reset")] + ConnectionReset, + /// The operation was interrupted before it could finish + #[error("operation interrupted")] + Interrupted, + /// Invalid internal data, if the argument data is invalid, use `InvalidInput` + #[error("invalid internal data")] + InvalidData, + /// The provided data is invalid + #[error("invalid input")] + InvalidInput, + /// Could not perform the operation because there was not an open connection + #[error("connection is not open")] + NotConnected, + /// The requested device couldn't be accessed + #[error("can't access device")] + NoDevice, + /// Caller was not allowed to perform this operation + #[error("permission denied")] + PermissionDenied, + /// The operation did not complete within the given amount of time + #[error("time out")] + TimedOut, + /// Found EOF when EOF was not expected + #[error("unexpected eof")] + UnexpectedEof, + /// Operation would block, this error lets the caller know that they can try again + #[error("blocking operation. try again")] + WouldBlock, + /// A call to write returned 0 + #[error("write returned 0")] + WriteZero, + /// The operation is not supported. + #[error("unsupported")] + Unsupported, + /// Some other unhandled error. If you see this, it's probably a bug. + #[error("unknown error found")] + UnknownError, +} + +pub fn net_error_into_io_err(net_error: NetworkError) -> std::io::Error { + use std::io::ErrorKind; + match net_error { + NetworkError::InvalidFd => ErrorKind::BrokenPipe.into(), + NetworkError::AlreadyExists => ErrorKind::AlreadyExists.into(), + NetworkError::Lock => ErrorKind::BrokenPipe.into(), + NetworkError::IOError => ErrorKind::BrokenPipe.into(), + NetworkError::AddressInUse => ErrorKind::AddrInUse.into(), + NetworkError::AddressNotAvailable => ErrorKind::AddrNotAvailable.into(), + NetworkError::BrokenPipe => ErrorKind::BrokenPipe.into(), + NetworkError::ConnectionAborted => ErrorKind::ConnectionAborted.into(), + NetworkError::ConnectionRefused => ErrorKind::ConnectionRefused.into(), + NetworkError::ConnectionReset => ErrorKind::ConnectionReset.into(), + NetworkError::Interrupted => ErrorKind::Interrupted.into(), + NetworkError::InvalidData => ErrorKind::InvalidData.into(), + NetworkError::InvalidInput => ErrorKind::InvalidInput.into(), + NetworkError::NotConnected => ErrorKind::NotConnected.into(), + NetworkError::NoDevice => ErrorKind::BrokenPipe.into(), + NetworkError::PermissionDenied => ErrorKind::PermissionDenied.into(), + NetworkError::TimedOut => ErrorKind::TimedOut.into(), + NetworkError::UnexpectedEof => ErrorKind::UnexpectedEof.into(), + NetworkError::WouldBlock => ErrorKind::WouldBlock.into(), + NetworkError::WriteZero => ErrorKind::WriteZero.into(), + NetworkError::Unsupported => ErrorKind::Unsupported.into(), + NetworkError::UnknownError => ErrorKind::BrokenPipe.into(), + } +} + +pub fn io_err_into_net_error(net_error: std::io::Error) -> NetworkError { + use std::io::ErrorKind; + match net_error.kind() { + ErrorKind::BrokenPipe => NetworkError::BrokenPipe, + ErrorKind::AlreadyExists => NetworkError::AlreadyExists, + ErrorKind::AddrInUse => NetworkError::AddressInUse, + ErrorKind::AddrNotAvailable => NetworkError::AddressNotAvailable, + ErrorKind::ConnectionAborted => NetworkError::ConnectionAborted, + ErrorKind::ConnectionRefused => NetworkError::ConnectionRefused, + ErrorKind::ConnectionReset => NetworkError::ConnectionReset, + ErrorKind::Interrupted => NetworkError::Interrupted, + ErrorKind::InvalidData => NetworkError::InvalidData, + ErrorKind::InvalidInput => NetworkError::InvalidInput, + ErrorKind::NotConnected => NetworkError::NotConnected, + ErrorKind::PermissionDenied => NetworkError::PermissionDenied, + ErrorKind::TimedOut => NetworkError::TimedOut, + ErrorKind::UnexpectedEof => NetworkError::UnexpectedEof, + ErrorKind::WouldBlock => NetworkError::WouldBlock, + ErrorKind::WriteZero => NetworkError::WriteZero, + ErrorKind::Unsupported => NetworkError::Unsupported, + _ => NetworkError::UnknownError, + } +} diff --git a/lib/wasi-local-networking/Cargo.toml b/lib/wasi-local-networking/Cargo.toml new file mode 100644 index 00000000000..ff18b704813 --- /dev/null +++ b/lib/wasi-local-networking/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "wasmer-wasi-local-networking" +version = "2.3.0" +description = "An WASIX extension for local networking" +categories = ["wasm"] +keywords = ["wasm", "webassembly", "types"] +authors = ["Wasmer Engineering Team "] +repository = "https://github.com/wasmerio/wasmer" +license = "MIT" +readme = "README.md" +edition = "2018" + +[badges] +maintenance = { status = "experimental" } + +[dependencies] +wasmer-vnet = { version = "=2.3.0", path = "../vnet", default-features = false } +wasmer-vfs = { path = "../vfs", version = "=2.3.0", default-features = false, features = [ "host-fs" ] } +tracing = "0.1" +bytes = "1.1" + +[features] +default = [ ] +wasix = [ ] diff --git a/lib/wasi-local-networking/README.md b/lib/wasi-local-networking/README.md new file mode 100644 index 00000000000..52a966a2046 --- /dev/null +++ b/lib/wasi-local-networking/README.md @@ -0,0 +1 @@ +This is experimental extension of WASIX for networking. diff --git a/lib/wasi-local-networking/src/lib.rs b/lib/wasi-local-networking/src/lib.rs new file mode 100644 index 00000000000..968902c0b12 --- /dev/null +++ b/lib/wasi-local-networking/src/lib.rs @@ -0,0 +1,810 @@ +#![allow(unused_variables)] +use std::time::Duration; +use std::net::{ + IpAddr, + SocketAddr, + Shutdown, Ipv6Addr, Ipv4Addr, +}; +use std::io::{ + Read, + Write, +}; +use bytes::{Bytes, BytesMut}; +use wasmer_vnet::{ + io_err_into_net_error, + VirtualConnectedSocket, + VirtualSocket, + VirtualNetworking, + VirtualWebSocket, + VirtualTcpListener, + VirtualRawSocket, + VirtualUdpSocket, + VirtualIcmpSocket, + VirtualTcpSocket, + SocketHttpRequest, + StreamSecurity, + SocketReceive, + SocketStatus, + IpCidr, + IpRoute, + TimeType, + Result, + NetworkError, VirtualConnectionlessSocket, SocketReceiveFrom +}; +#[allow(unused_imports, dead_code)] +use tracing::{debug, error, info, trace, warn}; + +#[derive(Debug, Default)] +pub struct LocalNetworking +{ +} + +#[allow(unused_variables)] +impl VirtualNetworking +for LocalNetworking +{ + fn ws_connect( + &self, + url: &str, + ) -> Result> { + Err(NetworkError::Unsupported) + } + + fn http_request( + &self, + url: &str, + method: &str, + headers: &str, + gzip: bool, + ) -> Result { + Err(NetworkError::Unsupported) + } + + fn bridge( + &self, + network: &str, + access_token: &str, + security: StreamSecurity, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn unbridge( + &self, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn dhcp_acquire( + &self, + ) -> Result> { + Err(NetworkError::Unsupported) + } + + fn ip_add( + &self, + ip: IpAddr, + prefix: u8, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn ip_remove( + &self, + ip: IpAddr, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn ip_clear( + &self, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn ip_list( + &self, + ) -> Result> { + Err(NetworkError::Unsupported) + } + + fn mac( + &self, + ) -> Result<[u8; 6]> { + Err(NetworkError::Unsupported) + } + + fn gateway_set( + &self, + ip: IpAddr, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn route_add( + &self, + cidr: IpCidr, + via_router: IpAddr, + preferred_until: Option, + expires_at: Option, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn route_remove( + &self, + cidr: IpAddr, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn route_clear( + &self, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn route_list( + &self, + ) -> Result> { + Err(NetworkError::Unsupported) + } + + fn bind_raw( + &self, + ) -> Result> { + Err(NetworkError::Unsupported) + } + + fn listen_tcp( + &self, + addr: SocketAddr, + only_v6: bool, + reuse_port: bool, + reuse_addr: bool, + ) -> Result> { + let listener = std::net::TcpListener::bind(addr) + .map(|sock| Box::new(LocalTcpListener { + stream: sock, + timeout: None, + })) + .map_err(io_err_into_net_error)?; + Ok(listener) + } + + fn bind_udp( + &self, + addr: SocketAddr, + _reuse_port: bool, + _reuse_addr: bool, + ) -> Result> { + let socket = std::net::UdpSocket::bind(addr) + .map_err(io_err_into_net_error)?; + Ok(Box::new(LocalUdpSocket(socket, addr))) + } + + fn bind_icmp( + &self, + addr: IpAddr, + ) -> Result> { + Err(NetworkError::Unsupported) + } + + fn connect_tcp( + &self, + _addr: SocketAddr, + peer: SocketAddr, + timeout: Option, + ) -> Result> { + let stream = if let Some(timeout) = timeout { + std::net::TcpStream::connect_timeout(&peer, timeout) + } else { + std::net::TcpStream::connect(peer) + } + .map_err(io_err_into_net_error)?; + let peer = stream.peer_addr() + .map_err(io_err_into_net_error)?; + Ok(Box::new(LocalTcpStream { + stream, + addr: peer, + connect_timeout: None, + })) + } + + fn resolve( + &self, + host: &str, + port: Option, + dns_server: Option, + ) -> Result> { + use std::net::ToSocketAddrs; + Ok( + if let Some(port) = port { + let host = format!("{}:{}", host, port); + host.to_socket_addrs() + .map(|a| a + .map(|a| a.ip()) + .collect::>()) + .map_err(io_err_into_net_error)? + } else { + host.to_socket_addrs() + .map(|a| a + .map(|a| a.ip()) + .collect::>()) + .map_err(io_err_into_net_error)? + } + ) + } +} + +#[derive(Debug)] +pub struct LocalTcpListener { + stream: std::net::TcpListener, + timeout: Option, +} + +impl VirtualTcpListener +for LocalTcpListener +{ + fn accept( + &self, + ) -> Result<(Box, SocketAddr)> { + if let Some(timeout) = &self.timeout { + return self.accept_timeout(timeout.clone()) + } + let (sock, addr) = self.stream.accept() + .map(|(sock, addr)| { + (Box::new(LocalTcpStream { + stream: sock, + addr: addr.clone(), + connect_timeout: None, + }), addr) + }) + .map_err(io_err_into_net_error)?; + Ok( + (sock, addr) + ) + } + + #[cfg(feature = "wasix")] + fn accept_timeout( + &self, + timeout: Duration, + ) -> Result<(Box, SocketAddr)> { + let (sock, addr) = self.stream.accept_timeout(timeout) + .map(|(sock, addr)| { + (Box::new(LocalTcpStream { + stream: sock, + addr: addr.clone(), + connect_timeout: None, + }), addr) + }) + .map_err(io_err_into_net_error)?; + Ok( + (sock, addr) + ) + } + + #[cfg(not(feature = "wasix"))] + fn accept_timeout( + &self, + _timeout: Duration, + ) -> Result<(Box, SocketAddr)> { + self.accept() + } + + /// Sets the accept timeout + fn set_timeout( + &mut self, + timeout: Option + ) -> Result<()> { + self.timeout = timeout; + Ok(()) + } + + /// Gets the accept timeout + fn timeout( + &self + ) -> Result> { + Ok(self.timeout.clone()) + } + + fn addr_local( + &self, + ) -> Result { + self.stream + .local_addr() + .map_err(io_err_into_net_error) + } + + fn set_ttl( + &mut self, + ttl: u8, + ) -> Result<()> { + self.stream + .set_ttl(ttl as u32) + .map_err(io_err_into_net_error) + } + + fn ttl( + &self, + ) -> Result { + self.stream + .ttl() + .map(|ttl| ttl as u8) + .map_err(io_err_into_net_error) + } +} + +#[derive(Debug)] +pub struct LocalTcpStream { + stream: std::net::TcpStream, + addr: SocketAddr, + connect_timeout: Option, +} + +impl VirtualTcpSocket +for LocalTcpStream +{ + fn set_opt_time( + &mut self, + ty: TimeType, + timeout: Option, + ) -> Result<()> { + match ty { + TimeType::ReadTimeout => self.stream.set_read_timeout(timeout).map_err(io_err_into_net_error), + TimeType::WriteTimeout => self.stream.set_write_timeout(timeout).map_err(io_err_into_net_error), + TimeType::ConnectTimeout => { + self.connect_timeout = timeout; + Ok(()) + }, + #[cfg(feature = "wasix")] + TimeType::Linger => self.stream.set_linger(timeout).map_err(io_err_into_net_error), + _ => Err(NetworkError::InvalidInput), + } + } + + fn opt_time( + &self, + ty: TimeType, + ) -> Result> { + match ty { + TimeType::ReadTimeout => self.stream.read_timeout().map_err(io_err_into_net_error), + TimeType::WriteTimeout => self.stream.write_timeout().map_err(io_err_into_net_error), + TimeType::ConnectTimeout => Ok(self.connect_timeout.clone()), + #[cfg(feature = "wasix")] + TimeType::Linger => self.stream.linger().map_err(io_err_into_net_error), + _ => Err(NetworkError::InvalidInput), + } + } + + fn set_recv_buf_size( + &mut self, + size: usize, + ) -> Result<()> { + Ok(()) + } + + fn recv_buf_size( + &self, + ) -> Result { + Err(NetworkError::Unsupported) + } + + fn set_send_buf_size( + &mut self, + size: usize, + ) -> Result<()> { + Ok(()) + } + + fn send_buf_size( + &self, + ) -> Result { + Err(NetworkError::Unsupported) + } + + fn set_nodelay( + &mut self, + nodelay: bool + ) -> Result<()> { + self.stream.set_nodelay(nodelay).map_err(io_err_into_net_error) + } + + fn nodelay( + &self, + ) -> Result { + self.stream.nodelay().map_err(io_err_into_net_error) + } + + fn addr_peer( + &self, + ) -> Result { + Ok(self.addr.clone()) + } + + fn flush( + &mut self, + ) -> Result<()> { + Ok(()) + } + + fn shutdown( + &mut self, + how: Shutdown, + ) -> Result<()> { + self.stream.shutdown(how).map_err(io_err_into_net_error) + } +} + +impl VirtualConnectedSocket +for LocalTcpStream +{ + fn set_linger( + &mut self, + linger: Option, + ) -> Result<()> { + #[cfg(feature = "wasix")] + self.stream.set_linger(linger).map_err(io_err_into_net_error)?; + Ok(()) + } + + #[cfg(feature = "wasix")] + fn linger( + &self, + ) -> Result> { + self.stream.linger().map_err(io_err_into_net_error) + } + + #[cfg(not(feature = "wasix"))] + fn linger( + &self, + ) -> Result> { + Ok(None) + } + + fn send( + &mut self, + data: Bytes, + ) -> Result { + self.stream.write_all(&data[..]) + .map(|_| data.len()) + .map_err(io_err_into_net_error) + } + + fn flush( + &mut self, + ) -> Result<()> { + self.stream.flush() + .map_err(io_err_into_net_error) + } + + fn recv( + &mut self, + ) -> Result { + let buf_size = 8192; + let mut buf = BytesMut::with_capacity(buf_size); + let read = self.stream.read(&mut buf[..]) + .map_err(io_err_into_net_error)?; + let buf = Bytes::from(buf).slice(..read); + Ok( + SocketReceive { + data: buf, + truncated: read == buf_size + } + ) + } + + fn peek( + &mut self, + ) -> Result { + let buf_size = 8192; + let mut buf = BytesMut::with_capacity(buf_size); + let read = self.stream.peek(&mut buf[..]) + .map_err(io_err_into_net_error)?; + let buf = Bytes::from(buf).slice(..read); + Ok( + SocketReceive { + data: buf, + truncated: read == buf_size + } + ) + } +} + +impl VirtualSocket +for LocalTcpStream +{ + fn set_ttl( + &mut self, + ttl: u32, + ) -> Result<()> { + self.stream.set_ttl(ttl) + .map_err(io_err_into_net_error) + } + + fn ttl( + &self, + ) -> Result { + self.stream.ttl() + .map_err(io_err_into_net_error) + } + + fn addr_local( + &self, + ) -> Result { + self.stream.local_addr() + .map_err(io_err_into_net_error) + } + + fn status( + &self, + ) -> Result { + Ok( + SocketStatus::Opened + ) + } +} + +#[derive(Debug)] +pub struct LocalUdpSocket(std::net::UdpSocket, SocketAddr); + +impl VirtualUdpSocket +for LocalUdpSocket +{ + fn connect( + &mut self, + addr: SocketAddr, + ) -> Result<()> { + self.0.connect(addr) + .map_err(io_err_into_net_error) + } + + fn set_broadcast( + &mut self, + broadcast: bool + ) -> Result<()> { + self.0.set_broadcast(broadcast) + .map_err(io_err_into_net_error) + } + + fn broadcast( + &self, + ) -> Result { + self.0.broadcast() + .map_err(io_err_into_net_error) + } + + fn set_multicast_loop_v4( + &mut self, + val: bool + ) -> Result<()> { + self.0.set_multicast_loop_v4(val) + .map_err(io_err_into_net_error) + } + + fn multicast_loop_v4( + &self, + ) -> Result { + self.0.multicast_loop_v4() + .map_err(io_err_into_net_error) + } + + fn set_multicast_loop_v6( + &mut self, + val: bool + ) -> Result<()> { + self.0.set_multicast_loop_v6(val) + .map_err(io_err_into_net_error) + } + + fn multicast_loop_v6( + &self, + ) -> Result { + self.0.multicast_loop_v6() + .map_err(io_err_into_net_error) + } + + fn set_multicast_ttl_v4( + &mut self, + ttl: u32, + ) -> Result<()> { + self.0.set_multicast_ttl_v4(ttl) + .map_err(io_err_into_net_error) + } + + fn multicast_ttl_v4( + &self, + ) -> Result { + self.0.multicast_ttl_v4() + .map_err(io_err_into_net_error) + } + + fn join_multicast_v4( + &mut self, + multiaddr: Ipv4Addr, + iface: Ipv4Addr, + ) -> Result<()> { + self.0.join_multicast_v4(&multiaddr, &iface) + .map_err(io_err_into_net_error) + } + + fn leave_multicast_v4( + &mut self, + multiaddr: Ipv4Addr, + iface: Ipv4Addr, + ) -> Result<()> { + self.0.leave_multicast_v4(&multiaddr, &iface) + .map_err(io_err_into_net_error) + } + + fn join_multicast_v6( + &mut self, + multiaddr: Ipv6Addr, + iface: u32, + ) -> Result<()> { + self.0.join_multicast_v6(&multiaddr, iface) + .map_err(io_err_into_net_error) + } + + fn leave_multicast_v6( + &mut self, + multiaddr: Ipv6Addr, + iface: u32, + ) -> Result<()> { + self.0.leave_multicast_v6(&multiaddr, iface) + .map_err(io_err_into_net_error) + } + + fn addr_peer( + &self, + ) -> Result> { + self.0.peer_addr() + .map(|a| Some(a)) + .map_err(io_err_into_net_error) + } +} + +impl VirtualConnectedSocket +for LocalUdpSocket +{ + fn set_linger( + &mut self, + linger: Option, + ) -> Result<()> { + Err(NetworkError::Unsupported) + } + + fn linger( + &self, + ) -> Result> { + Err(NetworkError::Unsupported) + } + + fn send( + &mut self, + data: Bytes, + ) -> Result { + self.0.send(&data[..]) + .map_err(io_err_into_net_error) + } + + fn flush( + &mut self, + ) -> Result<()> { + Ok(()) + } + + fn recv( + &mut self, + ) -> Result { + let buf_size = 8192; + let mut buf = BytesMut::with_capacity(buf_size); + let read = self.0.recv(&mut buf[..]) + .map_err(io_err_into_net_error)?; + let buf = Bytes::from(buf).slice(..read); + Ok( + SocketReceive { + data: buf, + truncated: read == buf_size + } + ) + } + + fn peek( + &mut self, + ) -> Result { + let buf_size = 8192; + let mut buf = BytesMut::with_capacity(buf_size); + let read = self.0.peek(&mut buf[..]) + .map_err(io_err_into_net_error)?; + let buf = Bytes::from(buf).slice(..read); + Ok( + SocketReceive { + data: buf, + truncated: read == buf_size + } + ) + } +} + +impl VirtualConnectionlessSocket +for LocalUdpSocket +{ + fn send_to( + &mut self, + data: Bytes, + addr: SocketAddr, + ) -> Result { + self.0.send_to(&data[..], addr) + .map_err(io_err_into_net_error) + } + + fn recv_from( + &mut self, + ) -> Result { + let buf_size = 8192; + let mut buf = BytesMut::with_capacity(buf_size); + let (read, peer) = self.0.recv_from(&mut buf[..]) + .map_err(io_err_into_net_error)?; + let buf = Bytes::from(buf).slice(..read); + Ok( + SocketReceiveFrom { + data: buf, + truncated: read == buf_size, + addr: peer + } + ) + } + + fn peek_from( + &mut self, + ) -> Result { + let buf_size = 8192; + let mut buf = BytesMut::with_capacity(buf_size); + let (read, peer) = self.0.peek_from(&mut buf[..]) + .map_err(io_err_into_net_error)?; + let buf = Bytes::from(buf).slice(..read); + Ok( + SocketReceiveFrom { + data: buf, + truncated: read == buf_size, + addr: peer + } + ) + } +} + +impl VirtualSocket +for LocalUdpSocket +{ + fn set_ttl( + &mut self, + ttl: u32, + ) -> Result<()> { + self.0.set_ttl(ttl) + .map_err(io_err_into_net_error) + } + + fn ttl( + &self, + ) -> Result { + self.0.ttl() + .map_err(io_err_into_net_error) + } + + fn addr_local( + &self, + ) -> Result { + self.0.local_addr() + .map_err(io_err_into_net_error) + } + + fn status( + &self, + ) -> Result { + Ok( + SocketStatus::Opened + ) + } +} diff --git a/lib/wasi-types/src/bus.rs b/lib/wasi-types/src/bus.rs new file mode 100644 index 00000000000..afc1073cc8a --- /dev/null +++ b/lib/wasi-types/src/bus.rs @@ -0,0 +1,86 @@ +use wasmer_derive::ValueType; +use wasmer_types::MemorySize; +use super::*; + +pub type __wasi_busdatatype_t = u8; +pub const __WASI_BUS_DATA_TYPE_CALL: __wasi_busdatatype_t = 0; +pub const __WASI_BUS_DATA_TYPE_CALLBACK: __wasi_busdatatype_t = 1; +pub const __WASI_BUS_DATA_TYPE_REPLY: __wasi_busdatatype_t = 2; + +pub type __wasi_busdataformat_t = u8; +pub const __WASI_BUS_DATA_FORMAT_RAW: __wasi_busdataformat_t = 0; +pub const __WASI_BUS_DATA_FORMAT_BINCODE: __wasi_busdataformat_t = 1; +pub const __WASI_BUS_DATA_FORMAT_MESSAGE_PACK: __wasi_busdataformat_t = 2; +pub const __WASI_BUS_DATA_FORMAT_JSON: __wasi_busdataformat_t = 3; +pub const __WASI_BUS_DATA_FORMAT_YAML: __wasi_busdataformat_t = 4; +pub const __WASI_BUS_DATA_FORMAT_XML: __wasi_busdataformat_t = 5; + +pub type __wasi_buseventtype_t = u8; +pub const __WASI_BUS_EVENT_TYPE_EXIT: __wasi_buseventtype_t = 0; +pub const __WASI_BUS_EVENT_TYPE_DATA: __wasi_buseventtype_t = 1; +pub const __WASI_BUS_EVENT_TYPE_FAULT: __wasi_buseventtype_t = 2; + +pub type __wasi_bid_t = u32; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_option_bid_t { + pub tag: __wasi_option_t, + pub bid: __wasi_bid_t, +} + +pub type __wasi_cid_t = u8; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_option_cid_t { + pub tag: __wasi_option_t, + pub cid: __wasi_cid_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_bus_handles_t { + pub handle: __wasi_bid_t, + pub stdin: __wasi_fd_t, + pub stdout: __wasi_fd_t, + pub stderr: __wasi_fd_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_busevent_exit_t { + pub rval: __wasi_exitcode_t +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_busevent_data_t { + pub ty: __wasi_busdatatype_t, + pub format: __wasi_busdataformat_t, + pub cid: __wasi_cid_t, + pub topic_len: M::Offset, + pub buf_len: M::Offset, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_busevent_fault_t { + pub cid: __wasi_cid_t, + pub err: __bus_errno_t, +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub union __wasi_busevent_u { + pub exit: __wasi_busevent_exit_t, + pub data: __wasi_busevent_data_t, + pub fault: __wasi_busevent_fault_t, +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct __wasi_busevent_t { + pub tag: __wasi_buseventtype_t, + pub u: __wasi_busevent_u, +} diff --git a/lib/wasi-types/src/error.rs b/lib/wasi-types/src/error.rs index 87d01bb0fac..fa1bf528126 100644 --- a/lib/wasi-types/src/error.rs +++ b/lib/wasi-types/src/error.rs @@ -76,3 +76,25 @@ pub const __WASI_ETIMEDOUT: u16 = 73; pub const __WASI_ETXTBSY: u16 = 74; pub const __WASI_EXDEV: u16 = 75; pub const __WASI_ENOTCAPABLE: u16 = 76; + +pub type __bus_errno_t = u32; +pub const __BUS_ESUCCESS: u32 = 0; +pub const __BUS_ESER: u32 = 1; +pub const __BUS_EDES: u32 = 2; +pub const __BUS_EWAPM: u32 = 3; +pub const __BUS_EFETCH: u32 = 4; +pub const __BUS_ECOMPILE: u32 = 5; +pub const __BUS_EABI: u32 = 6; +pub const __BUS_EABORTED: u32 = 7; +pub const __BUS_EBADHANDLE: u32 = 8; +pub const __BUS_ETOPIC: u32 = 9; +pub const __BUS_EBADCB: u32 = 10; +pub const __BUS_EUNSUPPORTED: u32 = 11; +pub const __BUS_EBADREQUEST: u32 = 12; +pub const __BUS_EDENIED: u32 = 13; +pub const __BUS_EINTERNAL: u32 = 14; +pub const __BUS_EALLOC: u32 = 15; +pub const __BUS_EINVOKE: u32 = 16; +pub const __BUS_ECONSUMED: u32 = 17; +pub const __BUS_EMEMVIOLATION: u32 = 18; +pub const __BUS_EUNKNOWN: u32 = 19; diff --git a/lib/wasi-types/src/file.rs b/lib/wasi-types/src/file.rs index 356a13398f8..0d58ba9bbe4 100644 --- a/lib/wasi-types/src/file.rs +++ b/lib/wasi-types/src/file.rs @@ -11,19 +11,25 @@ use wasmer_types::ValueType; pub type __wasi_device_t = u64; pub type __wasi_fd_t = u32; -pub const __WASI_STDIN_FILENO: u32 = 0; -pub const __WASI_STDOUT_FILENO: u32 = 1; -pub const __WASI_STDERR_FILENO: u32 = 2; +pub const __WASI_STDIN_FILENO: __wasi_fd_t = 0; +pub const __WASI_STDOUT_FILENO: __wasi_fd_t = 1; +pub const __WASI_STDERR_FILENO: __wasi_fd_t = 2; + +pub type __wasi_pid_t = u32; +pub type __wasi_tid_t = u32; pub type __wasi_fdflags_t = u16; -pub const __WASI_FDFLAG_APPEND: u16 = 1 << 0; -pub const __WASI_FDFLAG_DSYNC: u16 = 1 << 1; -pub const __WASI_FDFLAG_NONBLOCK: u16 = 1 << 2; -pub const __WASI_FDFLAG_RSYNC: u16 = 1 << 3; -pub const __WASI_FDFLAG_SYNC: u16 = 1 << 4; +pub const __WASI_FDFLAG_APPEND: __wasi_fdflags_t = 1 << 0; +pub const __WASI_FDFLAG_DSYNC: __wasi_fdflags_t = 1 << 1; +pub const __WASI_FDFLAG_NONBLOCK: __wasi_fdflags_t = 1 << 2; +pub const __WASI_FDFLAG_RSYNC: __wasi_fdflags_t = 1 << 3; +pub const __WASI_FDFLAG_SYNC: __wasi_fdflags_t = 1 << 4; + +pub type __wasi_eventfdflags = u16; +pub const __WASI_EVENTFDFLAGS_SEMAPHORE: __wasi_eventfdflags = 1 << 0; pub type __wasi_preopentype_t = u8; -pub const __WASI_PREOPENTYPE_DIR: u8 = 0; +pub const __WASI_PREOPENTYPE_DIR: __wasi_preopentype_t = 0; #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] @@ -204,64 +210,76 @@ pub fn wasi_filetype_to_name(ft: __wasi_filetype_t) -> &'static str { } pub type __wasi_filetype_t = u8; -pub const __WASI_FILETYPE_UNKNOWN: u8 = 0; -pub const __WASI_FILETYPE_BLOCK_DEVICE: u8 = 1; -pub const __WASI_FILETYPE_CHARACTER_DEVICE: u8 = 2; -pub const __WASI_FILETYPE_DIRECTORY: u8 = 3; -pub const __WASI_FILETYPE_REGULAR_FILE: u8 = 4; -pub const __WASI_FILETYPE_SOCKET_DGRAM: u8 = 5; -pub const __WASI_FILETYPE_SOCKET_STREAM: u8 = 6; -pub const __WASI_FILETYPE_SYMBOLIC_LINK: u8 = 7; +pub const __WASI_FILETYPE_UNKNOWN: __wasi_filetype_t = 0; +pub const __WASI_FILETYPE_BLOCK_DEVICE: __wasi_filetype_t = 1; +pub const __WASI_FILETYPE_CHARACTER_DEVICE: __wasi_filetype_t = 2; +pub const __WASI_FILETYPE_DIRECTORY: __wasi_filetype_t = 3; +pub const __WASI_FILETYPE_REGULAR_FILE: __wasi_filetype_t = 4; +pub const __WASI_FILETYPE_SOCKET_DGRAM: __wasi_filetype_t = 5; +pub const __WASI_FILETYPE_SOCKET_STREAM: __wasi_filetype_t = 6; +pub const __WASI_FILETYPE_SYMBOLIC_LINK: __wasi_filetype_t = 7; +pub const __WASI_FILETYPE_SOCKET_RAW: __wasi_filetype_t = 8; +pub const __WASI_FILETYPE_SOCKET_SEQPACKET: __wasi_filetype_t = 9; pub type __wasi_fstflags_t = u16; -pub const __WASI_FILESTAT_SET_ATIM: u16 = 1 << 0; -pub const __WASI_FILESTAT_SET_ATIM_NOW: u16 = 1 << 1; -pub const __WASI_FILESTAT_SET_MTIM: u16 = 1 << 2; -pub const __WASI_FILESTAT_SET_MTIM_NOW: u16 = 1 << 3; +pub const __WASI_FILESTAT_SET_ATIM: __wasi_fstflags_t = 1 << 0; +pub const __WASI_FILESTAT_SET_ATIM_NOW: __wasi_fstflags_t = 1 << 1; +pub const __WASI_FILESTAT_SET_MTIM: __wasi_fstflags_t = 1 << 2; +pub const __WASI_FILESTAT_SET_MTIM_NOW: __wasi_fstflags_t = 1 << 3; pub type __wasi_inode_t = u64; pub type __wasi_linkcount_t = u64; pub type __wasi_lookupflags_t = u32; -pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1 << 0; +pub const __WASI_LOOKUP_SYMLINK_FOLLOW: __wasi_lookupflags_t = 1 << 0; pub type __wasi_oflags_t = u16; -pub const __WASI_O_CREAT: u16 = 1 << 0; -pub const __WASI_O_DIRECTORY: u16 = 1 << 1; -pub const __WASI_O_EXCL: u16 = 1 << 2; -pub const __WASI_O_TRUNC: u16 = 1 << 3; +pub const __WASI_O_CREAT: __wasi_oflags_t = 1 << 0; +pub const __WASI_O_DIRECTORY: __wasi_oflags_t = 1 << 1; +pub const __WASI_O_EXCL: __wasi_oflags_t = 1 << 2; +pub const __WASI_O_TRUNC: __wasi_oflags_t = 1 << 3; pub type __wasi_rights_t = u64; -pub const __WASI_RIGHT_FD_DATASYNC: u64 = 1 << 0; -pub const __WASI_RIGHT_FD_READ: u64 = 1 << 1; -pub const __WASI_RIGHT_FD_SEEK: u64 = 1 << 2; -pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: u64 = 1 << 3; -pub const __WASI_RIGHT_FD_SYNC: u64 = 1 << 4; -pub const __WASI_RIGHT_FD_TELL: u64 = 1 << 5; -pub const __WASI_RIGHT_FD_WRITE: u64 = 1 << 6; -pub const __WASI_RIGHT_FD_ADVISE: u64 = 1 << 7; -pub const __WASI_RIGHT_FD_ALLOCATE: u64 = 1 << 8; -pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: u64 = 1 << 9; -pub const __WASI_RIGHT_PATH_CREATE_FILE: u64 = 1 << 10; -pub const __WASI_RIGHT_PATH_LINK_SOURCE: u64 = 1 << 11; -pub const __WASI_RIGHT_PATH_LINK_TARGET: u64 = 1 << 12; -pub const __WASI_RIGHT_PATH_OPEN: u64 = 1 << 13; -pub const __WASI_RIGHT_FD_READDIR: u64 = 1 << 14; -pub const __WASI_RIGHT_PATH_READLINK: u64 = 1 << 15; -pub const __WASI_RIGHT_PATH_RENAME_SOURCE: u64 = 1 << 16; -pub const __WASI_RIGHT_PATH_RENAME_TARGET: u64 = 1 << 17; -pub const __WASI_RIGHT_PATH_FILESTAT_GET: u64 = 1 << 18; -pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: u64 = 1 << 19; -pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: u64 = 1 << 20; -pub const __WASI_RIGHT_FD_FILESTAT_GET: u64 = 1 << 21; -pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u64 = 1 << 22; -pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u64 = 1 << 23; -pub const __WASI_RIGHT_PATH_SYMLINK: u64 = 1 << 24; -pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u64 = 1 << 25; -pub const __WASI_RIGHT_PATH_UNLINK_FILE: u64 = 1 << 26; -pub const __WASI_RIGHT_POLL_FD_READWRITE: u64 = 1 << 27; -pub const __WASI_RIGHT_SOCK_SHUTDOWN: u64 = 1 << 28; +pub const __WASI_RIGHT_FD_DATASYNC: __wasi_rights_t = 1 << 0; +pub const __WASI_RIGHT_FD_READ: __wasi_rights_t = 1 << 1; +pub const __WASI_RIGHT_FD_SEEK: __wasi_rights_t = 1 << 2; +pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: __wasi_rights_t = 1 << 3; +pub const __WASI_RIGHT_FD_SYNC: __wasi_rights_t = 1 << 4; +pub const __WASI_RIGHT_FD_TELL: __wasi_rights_t = 1 << 5; +pub const __WASI_RIGHT_FD_WRITE: __wasi_rights_t = 1 << 6; +pub const __WASI_RIGHT_FD_ADVISE: __wasi_rights_t = 1 << 7; +pub const __WASI_RIGHT_FD_ALLOCATE: __wasi_rights_t = 1 << 8; +pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: __wasi_rights_t = 1 << 9; +pub const __WASI_RIGHT_PATH_CREATE_FILE: __wasi_rights_t = 1 << 10; +pub const __WASI_RIGHT_PATH_LINK_SOURCE: __wasi_rights_t = 1 << 11; +pub const __WASI_RIGHT_PATH_LINK_TARGET: __wasi_rights_t = 1 << 12; +pub const __WASI_RIGHT_PATH_OPEN: __wasi_rights_t = 1 << 13; +pub const __WASI_RIGHT_FD_READDIR: __wasi_rights_t = 1 << 14; +pub const __WASI_RIGHT_PATH_READLINK: __wasi_rights_t = 1 << 15; +pub const __WASI_RIGHT_PATH_RENAME_SOURCE: __wasi_rights_t = 1 << 16; +pub const __WASI_RIGHT_PATH_RENAME_TARGET: __wasi_rights_t = 1 << 17; +pub const __WASI_RIGHT_PATH_FILESTAT_GET: __wasi_rights_t = 1 << 18; +pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: __wasi_rights_t = 1 << 19; +pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: __wasi_rights_t = 1 << 20; +pub const __WASI_RIGHT_FD_FILESTAT_GET: __wasi_rights_t = 1 << 21; +pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: __wasi_rights_t = 1 << 22; +pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: __wasi_rights_t = 1 << 23; +pub const __WASI_RIGHT_PATH_SYMLINK: __wasi_rights_t = 1 << 24; +pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: __wasi_rights_t = 1 << 25; +pub const __WASI_RIGHT_PATH_UNLINK_FILE: __wasi_rights_t = 1 << 26; +pub const __WASI_RIGHT_POLL_FD_READWRITE: __wasi_rights_t = 1 << 27; +pub const __WASI_RIGHT_SOCK_SHUTDOWN: __wasi_rights_t = 1 << 28; +pub const __WASI_RIGHT_SOCK_ACCEPT: __wasi_rights_t = 1 << 29; +pub const __WASI_RIGHT_SOCK_CONNECT: __wasi_rights_t = 1 << 30; +pub const __WASI_RIGHT_SOCK_LISTEN: __wasi_rights_t = 1 << 31; +pub const __WASI_RIGHT_SOCK_BIND: __wasi_rights_t = 1 << 32; +pub const __WASI_RIGHT_SOCK_RECV: __wasi_rights_t = 1 << 33; +pub const __WASI_RIGHT_SOCK_SEND: __wasi_rights_t = 1 << 34; +pub const __WASI_RIGHT_SOCK_ADDR_LOCAL: __wasi_rights_t = 1 << 35; +pub const __WASI_RIGHT_SOCK_ADDR_REMOTE: __wasi_rights_t = 1 << 36; +pub const __WASI_RIGHT_SOCK_RECV_FROM: __wasi_rights_t = 1 << 37; +pub const __WASI_RIGHT_SOCK_SEND_TO: __wasi_rights_t = 1 << 38; /// function for debugging rights issues #[allow(dead_code)] @@ -313,20 +331,7 @@ pub fn right_to_string(right: __wasi_rights_t) -> Option<&'static str> { }) } -pub type __wasi_riflags_t = u16; -pub const __WASI_SOCK_RECV_PEEK: u16 = 1 << 0; -pub const __WASI_SOCK_RECV_WAITALL: u16 = 1 << 1; - -pub type __wasi_roflags_t = u16; -pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u16 = 1 << 0; - pub type __wasi_whence_t = u8; -pub const __WASI_WHENCE_SET: u8 = 0; -pub const __WASI_WHENCE_CUR: u8 = 1; -pub const __WASI_WHENCE_END: u8 = 2; - -pub type __wasi_sdflags_t = u8; -pub const __WASI_SHUT_RD: u8 = 1 << 0; -pub const __WASI_SHUT_WR: u8 = 1 << 1; - -pub type __wasi_siflags_t = u16; +pub const __WASI_WHENCE_SET: __wasi_whence_t = 0; +pub const __WASI_WHENCE_CUR: __wasi_whence_t = 1; +pub const __WASI_WHENCE_END: __wasi_whence_t = 2; diff --git a/lib/wasi-types/src/io.rs b/lib/wasi-types/src/io.rs index 55d3fc5c1c6..f80ffcfb3eb 100644 --- a/lib/wasi-types/src/io.rs +++ b/lib/wasi-types/src/io.rs @@ -1,15 +1,55 @@ use wasmer_derive::ValueType; +use wasmer_types::MemorySize; + +use crate::__wasi_fd_t; + +pub type __wasi_count_t = u32; + +pub type __wasi_option_t = u8; +pub const __WASI_OPTION_NONE: __wasi_option_t = 0; +pub const __WASI_OPTION_SOME: __wasi_option_t = 1; + +pub type __wasi_bool_t = u8; +pub const __WASI_BOOL_FALSE: __wasi_bool_t = 0; +pub const __WASI_BOOL_TRUE: __wasi_bool_t = 1; #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] -pub struct __wasi_ciovec_t { - pub buf: u32, - pub buf_len: u32, +pub struct __wasi_ciovec_t { + pub buf: M::Offset, + pub buf_len: M::Offset, } #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] -pub struct __wasi_iovec_t { - pub buf: u32, - pub buf_len: u32, +pub struct __wasi_iovec_t { + pub buf: M::Offset, + pub buf_len: M::Offset, } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_tty_t { + pub cols: u32, + pub rows: u32, + pub width: u32, + pub height: u32, + pub stdin_tty: __wasi_bool_t, + pub stdout_tty: __wasi_bool_t, + pub stderr_tty: __wasi_bool_t, + pub echo: __wasi_bool_t, + pub line_buffered: __wasi_bool_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_pipe_handles_t { + pub pipe: __wasi_fd_t, + pub other: __wasi_fd_t, +} + +pub type __wasi_stdiomode_t = u8; +pub const __WASI_STDIO_MODE_PIPED: __wasi_stdiomode_t = 1; +pub const __WASI_STDIO_MODE_INHERIT: __wasi_stdiomode_t = 2; +pub const __WASI_STDIO_MODE_NULL: __wasi_stdiomode_t = 3; +pub const __WASI_STDIO_MODE_LOG: __wasi_stdiomode_t = 4; diff --git a/lib/wasi-types/src/lib.rs b/lib/wasi-types/src/lib.rs index 5a0acab713e..0eb568aa026 100644 --- a/lib/wasi-types/src/lib.rs +++ b/lib/wasi-types/src/lib.rs @@ -16,6 +16,8 @@ mod directory; mod error; mod event; mod file; +mod bus; +mod net; mod io; mod signal; mod subscription; @@ -28,6 +30,8 @@ pub use directory::*; pub use error::*; pub use event::*; pub use file::*; +pub use bus::*; +pub use net::*; pub use io::*; pub use signal::*; pub use subscription::*; diff --git a/lib/wasi-types/src/net.rs b/lib/wasi-types/src/net.rs new file mode 100644 index 00000000000..eb45892c759 --- /dev/null +++ b/lib/wasi-types/src/net.rs @@ -0,0 +1,494 @@ +use wasmer_derive::ValueType; +use super::*; + +use crate::__wasi_option_timestamp_t; + +pub type __wasi_socktype_t = u16; +pub const __WASI_SOCK_TYPE_DGRAM: __wasi_socktype_t = 0; +pub const __WASI_SOCK_TYPE_STREAM: __wasi_socktype_t = 1; +pub const __WASI_SOCK_TYPE_RAW: __wasi_socktype_t = 2; +pub const __WASI_SOCK_TYPE_SEQPACKET: __wasi_socktype_t = 3; + +pub type __wasi_sockstatus_t = u8; +pub const __WASI_SOCK_STATUS_OPENING: __wasi_sockstatus_t = 0; +pub const __WASI_SOCK_STATUS_OPENED: __wasi_sockstatus_t = 1; +pub const __WASI_SOCK_STATUS_CLOSED: __wasi_sockstatus_t = 2; +pub const __WASI_SOCK_STATUS_FAILED: __wasi_sockstatus_t = 3; + +pub type __wasi_sockoption_t = u8; +pub const __WASI_SOCK_OPTION_NOOP: __wasi_sockoption_t = 0; +pub const __WASI_SOCK_OPTION_REUSE_PORT: __wasi_sockoption_t = 1; +pub const __WASI_SOCK_OPTION_REUSE_ADDR: __wasi_sockoption_t = 2; +pub const __WASI_SOCK_OPTION_NO_DELAY: __wasi_sockoption_t = 3; +pub const __WASI_SOCK_OPTION_DONT_ROUTE: __wasi_sockoption_t = 4; +pub const __WASI_SOCK_OPTION_ONLY_V6: __wasi_sockoption_t = 5; +pub const __WASI_SOCK_OPTION_BROADCAST: __wasi_sockoption_t = 6; +pub const __WASI_SOCK_OPTION_MULTICAST_LOOP_V4: __wasi_sockoption_t = 7; +pub const __WASI_SOCK_OPTION_MULTICAST_LOOP_V6: __wasi_sockoption_t = 8; +pub const __WASI_SOCK_OPTION_PROMISCUOUS: __wasi_sockoption_t = 9; +pub const __WASI_SOCK_OPTION_LISTENING: __wasi_sockoption_t = 10; +pub const __WASI_SOCK_OPTION_LAST_ERROR: __wasi_sockoption_t = 11; +pub const __WASI_SOCK_OPTION_KEEP_ALIVE: __wasi_sockoption_t = 12; +pub const __WASI_SOCK_OPTION_LINGER: __wasi_sockoption_t = 13; +pub const __WASI_SOCK_OPTION_OOB_INLINE: __wasi_sockoption_t = 14; +pub const __WASI_SOCK_OPTION_RECV_BUF_SIZE: __wasi_sockoption_t = 15; +pub const __WASI_SOCK_OPTION_SEND_BUF_SIZE: __wasi_sockoption_t = 16; +pub const __WASI_SOCK_OPTION_RECV_LOWAT: __wasi_sockoption_t = 17; +pub const __WASI_SOCK_OPTION_SEND_LOWAT: __wasi_sockoption_t = 18; +pub const __WASI_SOCK_OPTION_RECV_TIMEOUT: __wasi_sockoption_t = 19; +pub const __WASI_SOCK_OPTION_SEND_TIMEOUT: __wasi_sockoption_t = 20; +pub const __WASI_SOCK_OPTION_CONNECT_TIMEOUT: __wasi_sockoption_t = 21; +pub const __WASI_SOCK_OPTION_ACCEPT_TIMEOUT: __wasi_sockoption_t = 22; +pub const __WASI_SOCK_OPTION_TTL: __wasi_sockoption_t = 23; +pub const __WASI_SOCK_OPTION_MULTICAST_TTL_V4: __wasi_sockoption_t = 24; +pub const __WASI_SOCK_OPTION_TYPE: __wasi_sockoption_t = 25; +pub const __WASI_SOCK_OPTION_PROTO: __wasi_sockoption_t = 26; + +pub type __wasi_streamsecurity_t = u8; +pub const __WASI_STREAM_SECURITY_UNENCRYPTED: __wasi_streamsecurity_t = 0; +pub const __WASI_STREAM_SECURITY_ANY_ENCRYPTION: __wasi_streamsecurity_t = 1; +pub const __WASI_STREAM_SECURITY_CLASSIC_ENCRYPTION: __wasi_streamsecurity_t = 2; +pub const __WASI_STREAM_SECURITY_DOUBLE_ENCRYPTION: __wasi_streamsecurity_t = 3; + +pub type __wasi_sockproto_t = u16; +pub const __WASI_SOCK_PROTO_IP: __wasi_sockproto_t = 0; +pub const __WASI_SOCK_PROTO_ICMP: __wasi_sockproto_t = 1; +pub const __WASI_SOCK_PROTO_IGMP: __wasi_sockproto_t = 2; +pub const __WASI_SOCK_PROTO_PROTO_3: __wasi_sockproto_t = 3; +pub const __WASI_SOCK_PROTO_IPIP: __wasi_sockproto_t = 4; +pub const __WASI_SOCK_PROTO_PROTO_5: __wasi_sockproto_t = 5; +pub const __WASI_SOCK_PROTO_TCP: __wasi_sockproto_t = 6; +pub const __WASI_SOCK_PROTO_PROTO_7: __wasi_sockproto_t = 7; +pub const __WASI_SOCK_PROTO_EGP: __wasi_sockproto_t = 8; +pub const __WASI_SOCK_PROTO_PROTO_9: __wasi_sockproto_t = 9; +pub const __WASI_SOCK_PROTO_PROTO_10: __wasi_sockproto_t = 10; +pub const __WASI_SOCK_PROTO_PROTO_11: __wasi_sockproto_t = 11; +pub const __WASI_SOCK_PROTO_PUP: __wasi_sockproto_t = 12; +pub const __WASI_SOCK_PROTO_PROTO_13: __wasi_sockproto_t = 13; +pub const __WASI_SOCK_PROTO_PROTO_14: __wasi_sockproto_t = 14; +pub const __WASI_SOCK_PROTO_PROTO_15: __wasi_sockproto_t = 15; +pub const __WASI_SOCK_PROTO_PROTO_16: __wasi_sockproto_t = 16; +pub const __WASI_SOCK_PROTO_UDP: __wasi_sockproto_t = 17; +pub const __WASI_SOCK_PROTO_PROTO_18: __wasi_sockproto_t = 18; +pub const __WASI_SOCK_PROTO_PROTO_19: __wasi_sockproto_t = 19; +pub const __WASI_SOCK_PROTO_PROTO_20: __wasi_sockproto_t = 20; +pub const __WASI_SOCK_PROTO_PROTO_21: __wasi_sockproto_t = 21; +pub const __WASI_SOCK_PROTO_IDP: __wasi_sockproto_t = 22; +pub const __WASI_SOCK_PROTO_PROTO_23: __wasi_sockproto_t = 23; +pub const __WASI_SOCK_PROTO_PROTO_24: __wasi_sockproto_t = 24; +pub const __WASI_SOCK_PROTO_PROTO_25: __wasi_sockproto_t = 25; +pub const __WASI_SOCK_PROTO_PROTO_26: __wasi_sockproto_t = 26; +pub const __WASI_SOCK_PROTO_PROTO_27: __wasi_sockproto_t = 27; +pub const __WASI_SOCK_PROTO_PROTO_28: __wasi_sockproto_t = 28; +pub const __WASI_SOCK_PROTO_PROTO_TP: __wasi_sockproto_t = 29; +pub const __WASI_SOCK_PROTO_PROTO_30: __wasi_sockproto_t = 30; +pub const __WASI_SOCK_PROTO_PROTO_31: __wasi_sockproto_t = 31; +pub const __WASI_SOCK_PROTO_PROTO_32: __wasi_sockproto_t = 32; +pub const __WASI_SOCK_PROTO_DCCP: __wasi_sockproto_t = 33; +pub const __WASI_SOCK_PROTO_PROTO_34: __wasi_sockproto_t = 34; +pub const __WASI_SOCK_PROTO_PROTO_35: __wasi_sockproto_t = 35; +pub const __WASI_SOCK_PROTO_PROTO_36: __wasi_sockproto_t = 36; +pub const __WASI_SOCK_PROTO_PROTO_37: __wasi_sockproto_t = 37; +pub const __WASI_SOCK_PROTO_PROTO_38: __wasi_sockproto_t = 38; +pub const __WASI_SOCK_PROTO_PROTO_39: __wasi_sockproto_t = 39; +pub const __WASI_SOCK_PROTO_PROTO_40: __wasi_sockproto_t = 40; +pub const __WASI_SOCK_PROTO_IPV6: __wasi_sockproto_t = 41; +pub const __WASI_SOCK_PROTO_PROTO_42: __wasi_sockproto_t = 42; +pub const __WASI_SOCK_PROTO_ROUTING: __wasi_sockproto_t = 43; +pub const __WASI_SOCK_PROTO_FRAGMENT: __wasi_sockproto_t = 44; +pub const __WASI_SOCK_PROTO_PROTO_45: __wasi_sockproto_t = 45; +pub const __WASI_SOCK_PROTO_RSVP: __wasi_sockproto_t = 46; +pub const __WASI_SOCK_PROTO_GRE: __wasi_sockproto_t = 47; +pub const __WASI_SOCK_PROTO_PROTO_48: __wasi_sockproto_t = 48; +pub const __WASI_SOCK_PROTO_PROTO_49: __wasi_sockproto_t = 49; +pub const __WASI_SOCK_PROTO_ESP: __wasi_sockproto_t = 50; +pub const __WASI_SOCK_PROTO_AH: __wasi_sockproto_t = 51; +pub const __WASI_SOCK_PROTO_PROTO_52: __wasi_sockproto_t = 52; +pub const __WASI_SOCK_PROTO_PROTO_53: __wasi_sockproto_t = 53; +pub const __WASI_SOCK_PROTO_PROTO_54: __wasi_sockproto_t = 54; +pub const __WASI_SOCK_PROTO_PROTO_55: __wasi_sockproto_t = 55; +pub const __WASI_SOCK_PROTO_PROTO_56: __wasi_sockproto_t = 56; +pub const __WASI_SOCK_PROTO_PROTO_57: __wasi_sockproto_t = 57; +pub const __WASI_SOCK_PROTO_ICMPV6: __wasi_sockproto_t = 58; +pub const __WASI_SOCK_PROTO_NONE: __wasi_sockproto_t = 59; +pub const __WASI_SOCK_PROTO_DSTOPTS: __wasi_sockproto_t = 60; +pub const __WASI_SOCK_PROTO_PROTO_61: __wasi_sockproto_t = 61; +pub const __WASI_SOCK_PROTO_PROTO_62: __wasi_sockproto_t = 62; +pub const __WASI_SOCK_PROTO_PROTO_63: __wasi_sockproto_t = 63; +pub const __WASI_SOCK_PROTO_PROTO_64: __wasi_sockproto_t = 64; +pub const __WASI_SOCK_PROTO_PROTO_65: __wasi_sockproto_t = 65; +pub const __WASI_SOCK_PROTO_PROTO_66: __wasi_sockproto_t = 66; +pub const __WASI_SOCK_PROTO_PROTO_67: __wasi_sockproto_t = 67; +pub const __WASI_SOCK_PROTO_PROTO_68: __wasi_sockproto_t = 68; +pub const __WASI_SOCK_PROTO_PROTO_69: __wasi_sockproto_t = 69; +pub const __WASI_SOCK_PROTO_PROTO_70: __wasi_sockproto_t = 70; +pub const __WASI_SOCK_PROTO_PROTO_71: __wasi_sockproto_t = 71; +pub const __WASI_SOCK_PROTO_PROTO_72: __wasi_sockproto_t = 72; +pub const __WASI_SOCK_PROTO_PROTO_73: __wasi_sockproto_t = 73; +pub const __WASI_SOCK_PROTO_PROTO_74: __wasi_sockproto_t = 74; +pub const __WASI_SOCK_PROTO_PROTO_75: __wasi_sockproto_t = 75; +pub const __WASI_SOCK_PROTO_PROTO_76: __wasi_sockproto_t = 76; +pub const __WASI_SOCK_PROTO_PROTO_77: __wasi_sockproto_t = 77; +pub const __WASI_SOCK_PROTO_PROTO_78: __wasi_sockproto_t = 78; +pub const __WASI_SOCK_PROTO_PROTO_79: __wasi_sockproto_t = 79; +pub const __WASI_SOCK_PROTO_PROTO_80: __wasi_sockproto_t = 80; +pub const __WASI_SOCK_PROTO_PROTO_81: __wasi_sockproto_t = 81; +pub const __WASI_SOCK_PROTO_PROTO_82: __wasi_sockproto_t = 82; +pub const __WASI_SOCK_PROTO_PROTO_83: __wasi_sockproto_t = 83; +pub const __WASI_SOCK_PROTO_PROTO_84: __wasi_sockproto_t = 84; +pub const __WASI_SOCK_PROTO_PROTO_85: __wasi_sockproto_t = 85; +pub const __WASI_SOCK_PROTO_PROTO_86: __wasi_sockproto_t = 86; +pub const __WASI_SOCK_PROTO_PROTO_87: __wasi_sockproto_t = 87; +pub const __WASI_SOCK_PROTO_PROTO_88: __wasi_sockproto_t = 88; +pub const __WASI_SOCK_PROTO_PROTO_89: __wasi_sockproto_t = 89; +pub const __WASI_SOCK_PROTO_PROTO_90: __wasi_sockproto_t = 90; +pub const __WASI_SOCK_PROTO_PROTO_91: __wasi_sockproto_t = 91; +pub const __WASI_SOCK_PROTO_MTP: __wasi_sockproto_t = 92; +pub const __WASI_SOCK_PROTO_PROTO_93: __wasi_sockproto_t = 93; +pub const __WASI_SOCK_PROTO_BEETPH: __wasi_sockproto_t = 94; +pub const __WASI_SOCK_PROTO_PROTO_95: __wasi_sockproto_t = 95; +pub const __WASI_SOCK_PROTO_PROTO_96: __wasi_sockproto_t = 96; +pub const __WASI_SOCK_PROTO_PROTO_97: __wasi_sockproto_t = 97; +pub const __WASI_SOCK_PROTO_ENCAP: __wasi_sockproto_t = 98; +pub const __WASI_SOCK_PROTO_PROTO_99: __wasi_sockproto_t = 99; +pub const __WASI_SOCK_PROTO_PROTO_100: __wasi_sockproto_t = 100; +pub const __WASI_SOCK_PROTO_PROTO_101: __wasi_sockproto_t = 101; +pub const __WASI_SOCK_PROTO_PROTO_102: __wasi_sockproto_t = 102; +pub const __WASI_SOCK_PROTO_PIM: __wasi_sockproto_t = 103; +pub const __WASI_SOCK_PROTO_PROTO_104: __wasi_sockproto_t = 104; +pub const __WASI_SOCK_PROTO_PROTO_105: __wasi_sockproto_t = 105; +pub const __WASI_SOCK_PROTO_PROTO_106: __wasi_sockproto_t = 106; +pub const __WASI_SOCK_PROTO_PROTO_107: __wasi_sockproto_t = 107; +pub const __WASI_SOCK_PROTO_COMP: __wasi_sockproto_t = 108; +pub const __WASI_SOCK_PROTO_PROTO_109: __wasi_sockproto_t = 109; +pub const __WASI_SOCK_PROTO_PROTO_110: __wasi_sockproto_t = 110; +pub const __WASI_SOCK_PROTO_PROTO_111: __wasi_sockproto_t = 111; +pub const __WASI_SOCK_PROTO_PROTO_112: __wasi_sockproto_t = 112; +pub const __WASI_SOCK_PROTO_PROTO_113: __wasi_sockproto_t = 113; +pub const __WASI_SOCK_PROTO_PROTO_114: __wasi_sockproto_t = 114; +pub const __WASI_SOCK_PROTO_PROTO_115: __wasi_sockproto_t = 115; +pub const __WASI_SOCK_PROTO_PROTO_116: __wasi_sockproto_t = 116; +pub const __WASI_SOCK_PROTO_PROTO_117: __wasi_sockproto_t = 117; +pub const __WASI_SOCK_PROTO_PROTO_118: __wasi_sockproto_t = 118; +pub const __WASI_SOCK_PROTO_PROTO_119: __wasi_sockproto_t = 119; +pub const __WASI_SOCK_PROTO_PROTO_120: __wasi_sockproto_t = 120; +pub const __WASI_SOCK_PROTO_PROTO_121: __wasi_sockproto_t = 121; +pub const __WASI_SOCK_PROTO_PROTO_122: __wasi_sockproto_t = 122; +pub const __WASI_SOCK_PROTO_PROTO_123: __wasi_sockproto_t = 123; +pub const __WASI_SOCK_PROTO_PROTO_124: __wasi_sockproto_t = 124; +pub const __WASI_SOCK_PROTO_PROTO_125: __wasi_sockproto_t = 125; +pub const __WASI_SOCK_PROTO_PROTO_126: __wasi_sockproto_t = 126; +pub const __WASI_SOCK_PROTO_PROTO_127: __wasi_sockproto_t = 127; +pub const __WASI_SOCK_PROTO_PROTO_128: __wasi_sockproto_t = 128; +pub const __WASI_SOCK_PROTO_PROTO_129: __wasi_sockproto_t = 129; +pub const __WASI_SOCK_PROTO_PROTO_130: __wasi_sockproto_t = 130; +pub const __WASI_SOCK_PROTO_PROTO_131: __wasi_sockproto_t = 131; +pub const __WASI_SOCK_PROTO_SCTP: __wasi_sockproto_t = 132; +pub const __WASI_SOCK_PROTO_PROTO_133: __wasi_sockproto_t = 133; +pub const __WASI_SOCK_PROTO_PROTO_134: __wasi_sockproto_t = 134; +pub const __WASI_SOCK_PROTO_MH: __wasi_sockproto_t = 135; +pub const __WASI_SOCK_PROTO_UDPLITE: __wasi_sockproto_t = 136; +pub const __WASI_SOCK_PROTO_MPLS: __wasi_sockproto_t = 137; +pub const __WASI_SOCK_PROTO_PROTO_138: __wasi_sockproto_t = 138; +pub const __WASI_SOCK_PROTO_PROTO_139: __wasi_sockproto_t = 139; +pub const __WASI_SOCK_PROTO_PROTO_140: __wasi_sockproto_t = 140; +pub const __WASI_SOCK_PROTO_PROTO_141: __wasi_sockproto_t = 141; +pub const __WASI_SOCK_PROTO_PROTO_142: __wasi_sockproto_t = 142; +pub const __WASI_SOCK_PROTO_ETHERNET: __wasi_sockproto_t = 143; +pub const __WASI_SOCK_PROTO_PROTO_144: __wasi_sockproto_t = 144; +pub const __WASI_SOCK_PROTO_PROTO_145: __wasi_sockproto_t = 145; +pub const __WASI_SOCK_PROTO_PROTO_146: __wasi_sockproto_t = 146; +pub const __WASI_SOCK_PROTO_PROTO_147: __wasi_sockproto_t = 147; +pub const __WASI_SOCK_PROTO_PROTO_148: __wasi_sockproto_t = 148; +pub const __WASI_SOCK_PROTO_PROTO_149: __wasi_sockproto_t = 149; +pub const __WASI_SOCK_PROTO_PROTO_150: __wasi_sockproto_t = 150; +pub const __WASI_SOCK_PROTO_PROTO_151: __wasi_sockproto_t = 151; +pub const __WASI_SOCK_PROTO_PROTO_152: __wasi_sockproto_t = 152; +pub const __WASI_SOCK_PROTO_PROTO_153: __wasi_sockproto_t = 153; +pub const __WASI_SOCK_PROTO_PROTO_154: __wasi_sockproto_t = 154; +pub const __WASI_SOCK_PROTO_PROTO_155: __wasi_sockproto_t = 155; +pub const __WASI_SOCK_PROTO_PROTO_156: __wasi_sockproto_t = 156; +pub const __WASI_SOCK_PROTO_PROTO_157: __wasi_sockproto_t = 157; +pub const __WASI_SOCK_PROTO_PROTO_158: __wasi_sockproto_t = 158; +pub const __WASI_SOCK_PROTO_PROTO_159: __wasi_sockproto_t = 159; +pub const __WASI_SOCK_PROTO_PROTO_160: __wasi_sockproto_t = 160; +pub const __WASI_SOCK_PROTO_PROTO_161: __wasi_sockproto_t = 161; +pub const __WASI_SOCK_PROTO_PROTO_162: __wasi_sockproto_t = 162; +pub const __WASI_SOCK_PROTO_PROTO_163: __wasi_sockproto_t = 163; +pub const __WASI_SOCK_PROTO_PROTO_164: __wasi_sockproto_t = 164; +pub const __WASI_SOCK_PROTO_PROTO_165: __wasi_sockproto_t = 165; +pub const __WASI_SOCK_PROTO_PROTO_166: __wasi_sockproto_t = 166; +pub const __WASI_SOCK_PROTO_PROTO_167: __wasi_sockproto_t = 167; +pub const __WASI_SOCK_PROTO_PROTO_168: __wasi_sockproto_t = 168; +pub const __WASI_SOCK_PROTO_PROTO_169: __wasi_sockproto_t = 169; +pub const __WASI_SOCK_PROTO_PROTO_170: __wasi_sockproto_t = 170; +pub const __WASI_SOCK_PROTO_PROTO_171: __wasi_sockproto_t = 171; +pub const __WASI_SOCK_PROTO_PROTO_172: __wasi_sockproto_t = 172; +pub const __WASI_SOCK_PROTO_PROTO_173: __wasi_sockproto_t = 173; +pub const __WASI_SOCK_PROTO_PROTO_174: __wasi_sockproto_t = 174; +pub const __WASI_SOCK_PROTO_PROTO_175: __wasi_sockproto_t = 175; +pub const __WASI_SOCK_PROTO_PROTO_176: __wasi_sockproto_t = 176; +pub const __WASI_SOCK_PROTO_PROTO_177: __wasi_sockproto_t = 177; +pub const __WASI_SOCK_PROTO_PROTO_178: __wasi_sockproto_t = 178; +pub const __WASI_SOCK_PROTO_PROTO_179: __wasi_sockproto_t = 179; +pub const __WASI_SOCK_PROTO_PROTO_180: __wasi_sockproto_t = 180; +pub const __WASI_SOCK_PROTO_PROTO_181: __wasi_sockproto_t = 181; +pub const __WASI_SOCK_PROTO_PROTO_182: __wasi_sockproto_t = 182; +pub const __WASI_SOCK_PROTO_PROTO_183: __wasi_sockproto_t = 183; +pub const __WASI_SOCK_PROTO_PROTO_184: __wasi_sockproto_t = 184; +pub const __WASI_SOCK_PROTO_PROTO_185: __wasi_sockproto_t = 185; +pub const __WASI_SOCK_PROTO_PROTO_186: __wasi_sockproto_t = 186; +pub const __WASI_SOCK_PROTO_PROTO_187: __wasi_sockproto_t = 187; +pub const __WASI_SOCK_PROTO_PROTO_188: __wasi_sockproto_t = 188; +pub const __WASI_SOCK_PROTO_PROTO_189: __wasi_sockproto_t = 189; +pub const __WASI_SOCK_PROTO_PROTO_190: __wasi_sockproto_t = 190; +pub const __WASI_SOCK_PROTO_PROTO_191: __wasi_sockproto_t = 191; +pub const __WASI_SOCK_PROTO_PROTO_192: __wasi_sockproto_t = 192; +pub const __WASI_SOCK_PROTO_PROTO_193: __wasi_sockproto_t = 193; +pub const __WASI_SOCK_PROTO_PROTO_194: __wasi_sockproto_t = 194; +pub const __WASI_SOCK_PROTO_PROTO_195: __wasi_sockproto_t = 195; +pub const __WASI_SOCK_PROTO_PROTO_196: __wasi_sockproto_t = 196; +pub const __WASI_SOCK_PROTO_PROTO_197: __wasi_sockproto_t = 197; +pub const __WASI_SOCK_PROTO_PROTO_198: __wasi_sockproto_t = 198; +pub const __WASI_SOCK_PROTO_PROTO_199: __wasi_sockproto_t = 199; +pub const __WASI_SOCK_PROTO_PROTO_200: __wasi_sockproto_t = 200; +pub const __WASI_SOCK_PROTO_PROTO_201: __wasi_sockproto_t = 201; +pub const __WASI_SOCK_PROTO_PROTO_202: __wasi_sockproto_t = 202; +pub const __WASI_SOCK_PROTO_PROTO_203: __wasi_sockproto_t = 203; +pub const __WASI_SOCK_PROTO_PROTO_204: __wasi_sockproto_t = 204; +pub const __WASI_SOCK_PROTO_PROTO_205: __wasi_sockproto_t = 205; +pub const __WASI_SOCK_PROTO_PROTO_206: __wasi_sockproto_t = 206; +pub const __WASI_SOCK_PROTO_PROTO_207: __wasi_sockproto_t = 207; +pub const __WASI_SOCK_PROTO_PROTO_208: __wasi_sockproto_t = 208; +pub const __WASI_SOCK_PROTO_PROTO_209: __wasi_sockproto_t = 209; +pub const __WASI_SOCK_PROTO_PROTO_210: __wasi_sockproto_t = 210; +pub const __WASI_SOCK_PROTO_PROTO_211: __wasi_sockproto_t = 211; +pub const __WASI_SOCK_PROTO_PROTO_212: __wasi_sockproto_t = 212; +pub const __WASI_SOCK_PROTO_PROTO_213: __wasi_sockproto_t = 213; +pub const __WASI_SOCK_PROTO_PROTO_214: __wasi_sockproto_t = 214; +pub const __WASI_SOCK_PROTO_PROTO_215: __wasi_sockproto_t = 215; +pub const __WASI_SOCK_PROTO_PROTO_216: __wasi_sockproto_t = 216; +pub const __WASI_SOCK_PROTO_PROTO_217: __wasi_sockproto_t = 217; +pub const __WASI_SOCK_PROTO_PROTO_218: __wasi_sockproto_t = 218; +pub const __WASI_SOCK_PROTO_PROTO_219: __wasi_sockproto_t = 219; +pub const __WASI_SOCK_PROTO_PROTO_220: __wasi_sockproto_t = 220; +pub const __WASI_SOCK_PROTO_PROTO_221: __wasi_sockproto_t = 221; +pub const __WASI_SOCK_PROTO_PROTO_222: __wasi_sockproto_t = 222; +pub const __WASI_SOCK_PROTO_PROTO_223: __wasi_sockproto_t = 223; +pub const __WASI_SOCK_PROTO_PROTO_224: __wasi_sockproto_t = 224; +pub const __WASI_SOCK_PROTO_PROTO_225: __wasi_sockproto_t = 225; +pub const __WASI_SOCK_PROTO_PROTO_226: __wasi_sockproto_t = 226; +pub const __WASI_SOCK_PROTO_PROTO_227: __wasi_sockproto_t = 227; +pub const __WASI_SOCK_PROTO_PROTO_228: __wasi_sockproto_t = 228; +pub const __WASI_SOCK_PROTO_PROTO_229: __wasi_sockproto_t = 229; +pub const __WASI_SOCK_PROTO_PROTO_230: __wasi_sockproto_t = 230; +pub const __WASI_SOCK_PROTO_PROTO_231: __wasi_sockproto_t = 231; +pub const __WASI_SOCK_PROTO_PROTO_232: __wasi_sockproto_t = 232; +pub const __WASI_SOCK_PROTO_PROTO_233: __wasi_sockproto_t = 233; +pub const __WASI_SOCK_PROTO_PROTO_234: __wasi_sockproto_t = 234; +pub const __WASI_SOCK_PROTO_PROTO_235: __wasi_sockproto_t = 235; +pub const __WASI_SOCK_PROTO_PROTO_236: __wasi_sockproto_t = 236; +pub const __WASI_SOCK_PROTO_PROTO_237: __wasi_sockproto_t = 237; +pub const __WASI_SOCK_PROTO_PROTO_238: __wasi_sockproto_t = 238; +pub const __WASI_SOCK_PROTO_PROTO_239: __wasi_sockproto_t = 239; +pub const __WASI_SOCK_PROTO_PROTO_240: __wasi_sockproto_t = 240; +pub const __WASI_SOCK_PROTO_PROTO_241: __wasi_sockproto_t = 241; +pub const __WASI_SOCK_PROTO_PROTO_242: __wasi_sockproto_t = 242; +pub const __WASI_SOCK_PROTO_PROTO_243: __wasi_sockproto_t = 243; +pub const __WASI_SOCK_PROTO_PROTO_244: __wasi_sockproto_t = 244; +pub const __WASI_SOCK_PROTO_PROTO_245: __wasi_sockproto_t = 245; +pub const __WASI_SOCK_PROTO_PROTO_246: __wasi_sockproto_t = 246; +pub const __WASI_SOCK_PROTO_PROTO_247: __wasi_sockproto_t = 247; +pub const __WASI_SOCK_PROTO_PROTO_248: __wasi_sockproto_t = 248; +pub const __WASI_SOCK_PROTO_PROTO_249: __wasi_sockproto_t = 249; +pub const __WASI_SOCK_PROTO_PROTO_250: __wasi_sockproto_t = 250; +pub const __WASI_SOCK_PROTO_PROTO_251: __wasi_sockproto_t = 251; +pub const __WASI_SOCK_PROTO_PROTO_252: __wasi_sockproto_t = 252; +pub const __WASI_SOCK_PROTO_PROTO_253: __wasi_sockproto_t = 253; +pub const __WASI_SOCK_PROTO_PROTO_254: __wasi_sockproto_t = 254; +pub const __WASI_SOCK_PROTO_PROTO_RAW: __wasi_sockproto_t = 255; +pub const __WASI_SOCK_PROTO_PROTO_256: __wasi_sockproto_t = 256; +pub const __WASI_SOCK_PROTO_PROTO_257: __wasi_sockproto_t = 257; +pub const __WASI_SOCK_PROTO_PROTO_258: __wasi_sockproto_t = 258; +pub const __WASI_SOCK_PROTO_PROTO_259: __wasi_sockproto_t = 259; +pub const __WASI_SOCK_PROTO_PROTO_260: __wasi_sockproto_t = 260; +pub const __WASI_SOCK_PROTO_PROTO_261: __wasi_sockproto_t = 261; +pub const __WASI_SOCK_PROTO_MPTCP: __wasi_sockproto_t = 262; +pub const __WASI_SOCK_PROTO_MAX: __wasi_sockproto_t = 263; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_hardwareaddress_t { + pub octs: [u8; 6], +} + +pub type __wasi_addressfamily_t = u16; +pub const __WASI_ADDRESS_FAMILY_UNSPEC: __wasi_addressfamily_t = 0; +pub const __WASI_ADDRESS_FAMILY_INET4: __wasi_addressfamily_t = 1; +pub const __WASI_ADDRESS_FAMILY_INET6: __wasi_addressfamily_t = 2; +pub const __WASI_ADDRESS_FAMILY_UNIX: __wasi_addressfamily_t = 3; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_addr_unspec_t { + pub n0: u8, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_addr_unspec_port_t { + pub port: u16, + pub addr: __wasi_addr_unspec_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_cidr_unspec_t { + pub addr: __wasi_addr_unspec_t, + pub prefix: u8, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_addr_ip4_t { + pub octs: [u8; 4], +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_addr_ip4_port_t { + pub port: u16, + pub ip: __wasi_addr_ip4_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_cidr_ip4_t { + pub ip: __wasi_addr_ip4_t, + pub prefix: u8, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_addr_unix_t { + pub octs: [u8; 16], +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_addr_unix_port_t { + pub port: u16, + pub unix: __wasi_addr_unix_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_cidr_unix_t { + pub unix: __wasi_addr_unix_t, + pub prefix: u8, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_addr_ip6_t { + pub segs: [u8; 16], +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_addr_ip6_port_t { + pub port: u16, + pub ip: __wasi_addr_ip6_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_cidr_ip6_t { + pub ip: __wasi_addr_ip6_t, + pub prefix: u8, +} + +#[derive(Debug, Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_addr_u { + pub octs: [u8; 16], +} + +#[derive(Debug, Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_addr_t { + pub tag: __wasi_addressfamily_t, + pub u: __wasi_addr_u, +} + +#[derive(Debug, Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_addr_port_u { + pub octs: [u8; 18], +} + +#[derive(Debug, Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_addr_port_t { + pub tag: __wasi_addressfamily_t, + pub u: __wasi_addr_port_u, +} + +#[derive(Debug, Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_cidr_u { + pub octs: [u8; 17], +} + +#[derive(Debug, Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_cidr_t { + pub tag: __wasi_addressfamily_t, + pub u: __wasi_cidr_u, +} + +#[derive(Debug, Copy, Clone, ValueType)] +#[repr(C)] +pub struct __wasi_route_t { + pub cidr: __wasi_cidr_t, + pub via_router: __wasi_addr_t, + pub preferred_until: __wasi_option_timestamp_t, + pub expires_at: __wasi_option_timestamp_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_http_handles_t { + pub req: __wasi_fd_t, + pub res: __wasi_fd_t, + pub hdr: __wasi_fd_t, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_http_status_t { + pub ok: __wasi_bool_t, + pub redirect: __wasi_bool_t, + pub size: __wasi_filesize_t, + pub status: u16, +} + +pub type __wasi_riflags_t = u16; +pub const __WASI_SOCK_RECV_INPUT_PEEK: __wasi_riflags_t = 1 << 0; +pub const __WASI_SOCK_RECV_INPUT_WAITALL: __wasi_riflags_t = 1 << 1; +pub const __WASI_SOCK_RECV_INPUT_DATA_TRUNCATED: __wasi_riflags_t = 1 << 2; + +pub type __wasi_roflags_t = u16; +pub const __WASI_SOCK_RECV_OUTPUT_DATA_TRUNCATED: __wasi_roflags_t = 1 << 0; + +pub type __wasi_sdflags_t = u8; +pub const __WASI_SHUT_RD: __wasi_sdflags_t = 1 << 0; +pub const __WASI_SHUT_WR: __wasi_sdflags_t = 1 << 1; + +pub type __wasi_siflags_t = u16; + +pub type __wasi_timeout_t = u8; +pub const __WASI_TIMEOUT_READ: __wasi_timeout_t = 0; +pub const __WASI_TIMEOUT_WRITE: __wasi_timeout_t = 1; +pub const __WASI_TIMEOUT_CONNECT: __wasi_timeout_t = 2; +pub const __WASI_TIMEOUT_ACCEPT: __wasi_timeout_t = 3; diff --git a/lib/wasi-types/src/time.rs b/lib/wasi-types/src/time.rs index 85b3ef05f12..f39514835cd 100644 --- a/lib/wasi-types/src/time.rs +++ b/lib/wasi-types/src/time.rs @@ -1,7 +1,17 @@ +use wasmer_derive::ValueType; +use super::io::__wasi_option_t; + pub type __wasi_clockid_t = u32; -pub const __WASI_CLOCK_REALTIME: u32 = 0; -pub const __WASI_CLOCK_MONOTONIC: u32 = 1; -pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 2; -pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3; +pub const __WASI_CLOCK_REALTIME: __wasi_clockid_t = 0; +pub const __WASI_CLOCK_MONOTONIC: __wasi_clockid_t = 1; +pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: __wasi_clockid_t = 2; +pub const __WASI_CLOCK_THREAD_CPUTIME_ID: __wasi_clockid_t = 3; pub type __wasi_timestamp_t = u64; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_option_timestamp_t { + pub tag: __wasi_option_t, + pub u: __wasi_timestamp_t, +} diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 7d85a721d17..d05400926b3 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -22,11 +22,15 @@ getrandom = "0.2" wasmer-wasi-types = { path = "../wasi-types", version = "=2.3.0" } wasmer = { path = "../api", version = "=2.3.0", default-features = false } wasmer-vfs = { path = "../vfs", version = "=2.3.0", default-features = false } +wasmer-vbus = { path = "../vbus", version = "=2.3.0", default-features = false } +wasmer-vnet = { path = "../vnet", version = "=2.3.0", default-features = false } +wasmer-wasi-local-networking = { path = "../wasi-local-networking", version = "=2.3.0", default-features = false, optional = true } typetag = { version = "0.1", optional = true } serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } bincode = { version = "1.3", optional = true } chrono = { version = "^0.4", features = [ "wasmbind" ], optional = true } derivative = { version = "^2" } +bytes = "1" [target.'cfg(unix)'.dependencies] libc = { version = "^0.2", default-features = false } @@ -45,13 +49,14 @@ tracing-wasm = "0.2" default = ["sys-default"] sys = ["wasmer/sys"] -sys-default = ["wasmer/sys-default", "sys", "logging", "host-fs", "sys-poll"] +sys-default = ["wasmer/sys-default", "sys", "logging", "host-fs", "sys-poll", "host-vnet" ] sys-poll = [] js = ["wasmer/js", "mem-fs", "wasmer-vfs/no-time", "getrandom/js", "chrono"] js-default = ["js", "wasmer/js-default"] test-js = ["js", "wasmer/js-default", "wasmer/wat"] +host-vnet = [ "wasmer-wasi-local-networking" ] host-fs = ["wasmer-vfs/host-fs"] mem-fs = ["wasmer-vfs/mem-fs"] diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index bb5506add10..b390eda62d7 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -38,6 +38,7 @@ mod macros; mod state; mod syscalls; mod utils; +mod runtime; use crate::syscalls::*; @@ -52,6 +53,8 @@ pub use wasmer_vfs::FsError as WasiFsError; #[deprecated(since = "2.1.0", note = "Please use `wasmer_vfs::VirtualFile`")] pub use wasmer_vfs::VirtualFile as WasiFile; pub use wasmer_vfs::{FsError, VirtualFile}; +pub use wasmer_vbus::{VirtualBus, UnsupportedVirtualBus}; +pub use wasmer_vnet::{VirtualNetworking, UnsupportedVirtualNetworking}; use wasmer_wasi_types::__WASI_CLOCK_MONOTONIC; use derivative::*; @@ -59,10 +62,12 @@ use std::ops::Deref; use thiserror::Error; use wasmer::{ imports, Function, Imports, LazyInit, Memory, MemoryAccessError, Module, Store, WasmerEnv, + MemorySize, Memory32, }; use std::time::Duration; -use std::sync::{atomic::AtomicU32, atomic::Ordering, Arc, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::{Arc, RwLockReadGuard, RwLockWriteGuard}; +pub use runtime::{WasiRuntimeImplementation, PlugableRuntimeImplementation, WasiThreadError, WasiTtyState}; /// This is returned in `RuntimeError`. /// Use `downcast` or `downcast_ref` to retrieve the `ExitCode`. @@ -74,11 +79,22 @@ pub enum WasiError { UnknownWasiVersion, } +/// Represents the ID of a WASI thread +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct WasiThreadId(u32); + +impl From for WasiThreadId { + fn from(id: u32) -> Self { Self(id) } +} +impl Into for WasiThreadId { + fn into(self) -> u32 { self.0 } +} + /// WASI processes can have multiple threads attached to the same environment #[derive(Debug, Clone, WasmerEnv)] pub struct WasiThread { /// ID of this thread - id: u32, + id: WasiThreadId, /// Provides access to the WASI environment env: WasiEnv, #[wasmer(export)] @@ -96,21 +112,13 @@ impl Deref for WasiThread { impl WasiThread { /// Returns the unique ID of this thread - pub fn thread_id(&self) -> u32 { + pub fn thread_id(&self) -> WasiThreadId { self.id } - /// Yields execution - pub fn yield_callback(&self) -> Result<(), WasiError> { - if let Some(callback) = self.on_yield.as_ref() { - callback(self)?; - } - Ok(()) - } - // Yields execution pub fn yield_now(&self) -> Result<(), WasiError> { - self.yield_callback()?; + self.env.runtime.yield_now(self.id)?; Ok(()) } @@ -138,6 +146,16 @@ impl WasiThread { Ok(()) } + /// Accesses the virtual networking implementation + pub fn net<'a>(&'a self) -> &'a (dyn VirtualNetworking) { + self.env.runtime.networking() + } + + /// Accesses the virtual bus implementation + pub fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { + self.env.runtime.bus() + } + /// Get a reference to the memory pub fn memory(&self) -> &Memory { self.memory_ref() @@ -215,18 +233,9 @@ pub struct WasiEnv { memory: LazyInit, /// Shared state of the WASI system. Manages all the data that the /// executing WASI program can see. - /// - /// Holding a read lock across WASM calls now is allowed pub state: Arc, - /// Optional callback thats invoked whenever a syscall is made - /// which is used to make callbacks to the process without breaking - /// the single threaded WASM modules - #[derivative(Debug = "ignore")] - pub(crate) on_yield: Option Result<(), WasiError> + Send + Sync + 'static>>, - /// The thread ID seed is used to generate unique thread identifiers - /// for each WasiThread. These are needed for multithreading code that needs - /// this information in the syscalls - pub(crate) thread_id_seed: Arc, + /// Implementation of the WASI runtime. + pub(crate) runtime: Arc, } impl WasiEnv { @@ -234,15 +243,26 @@ impl WasiEnv { Self { state: Arc::new(state), memory: LazyInit::new(), - on_yield: None, - thread_id_seed: Arc::new(AtomicU32::new(1u32)), + runtime: Arc::new(PlugableRuntimeImplementation::default()), } } + /// Returns a copy of the current runtime implementation for this environment + pub fn runtime<'a>(&'a self) -> &'a (dyn WasiRuntimeImplementation) { + self.runtime.deref() + } + + /// Overrides the runtime implementation for this environment + pub fn set_runtime(&mut self, runtime: R) + where R: WasiRuntimeImplementation + Send + Sync + 'static + { + self.runtime = Arc::new(runtime); + } + /// Creates a new thread only this wasi environment pub fn new_thread(&self) -> WasiThread { WasiThread { - id: self.thread_id_seed.fetch_add(1, Ordering::Relaxed), + id: self.runtime.thread_generate_id(), env: self.clone(), memory: self.memory_clone(), } @@ -281,6 +301,8 @@ pub fn generate_import_object_from_thread( ) -> Imports { match version { WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, thread), + WasiVersion::Wasix32v1 => generate_import_object_wasix32_v1(store, thread), + WasiVersion::Wasix64v1 => generate_import_object_wasix64_v1(store, thread), WasiVersion::Snapshot1 | WasiVersion::Latest => { generate_import_object_snapshot1(store, thread) } @@ -289,6 +311,7 @@ pub fn generate_import_object_from_thread( /// Combines a state generating function with the import list for legacy WASI fn generate_import_object_snapshot0(store: &Store, thread: WasiThread) -> Imports { + use self::wasi::*; imports! { "wasi_unstable" => { "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), @@ -342,6 +365,7 @@ fn generate_import_object_snapshot0(store: &Store, thread: WasiThread) -> Import /// Combines a state generating function with the import list for snapshot 1 fn generate_import_object_snapshot1(store: &Store, thread: WasiThread) -> Imports { + use self::wasi::*; imports! { "wasi_snapshot_preview1" => { "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), @@ -393,6 +417,239 @@ fn generate_import_object_snapshot1(store: &Store, thread: WasiThread) -> Import } } +/// Combines a state generating function with the import list for snapshot 1 +fn generate_import_object_wasix32_v1(store: &Store, thread: WasiThread) -> Imports { + use self::wasix32::*; + imports! { + "wasix_32v1" => { + "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), + "args_sizes_get" => Function::new_native_with_env(store, thread.clone(), args_sizes_get), + "clock_res_get" => Function::new_native_with_env(store, thread.clone(), clock_res_get), + "clock_time_get" => Function::new_native_with_env(store, thread.clone(), clock_time_get), + "environ_get" => Function::new_native_with_env(store, thread.clone(), environ_get), + "environ_sizes_get" => Function::new_native_with_env(store, thread.clone(), environ_sizes_get), + "fd_advise" => Function::new_native_with_env(store, thread.clone(), fd_advise), + "fd_allocate" => Function::new_native_with_env(store, thread.clone(), fd_allocate), + "fd_close" => Function::new_native_with_env(store, thread.clone(), fd_close), + "fd_datasync" => Function::new_native_with_env(store, thread.clone(), fd_datasync), + "fd_fdstat_get" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_get), + "fd_fdstat_set_flags" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native_with_env(store, thread.clone(), fd_filestat_get), + "fd_filestat_set_size" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_times), + "fd_pread" => Function::new_native_with_env(store, thread.clone(), fd_pread), + "fd_prestat_get" => Function::new_native_with_env(store, thread.clone(), fd_prestat_get), + "fd_prestat_dir_name" => Function::new_native_with_env(store, thread.clone(), fd_prestat_dir_name), + "fd_pwrite" => Function::new_native_with_env(store, thread.clone(), fd_pwrite), + "fd_read" => Function::new_native_with_env(store, thread.clone(), fd_read), + "fd_readdir" => Function::new_native_with_env(store, thread.clone(), fd_readdir), + "fd_renumber" => Function::new_native_with_env(store, thread.clone(), fd_renumber), + "fd_dup" => Function::new_native_with_env(store, thread.clone(), fd_dup), + "fd_event" => Function::new_native_with_env(store, thread.clone(), fd_event), + "fd_seek" => Function::new_native_with_env(store, thread.clone(), fd_seek), + "fd_sync" => Function::new_native_with_env(store, thread.clone(), fd_sync), + "fd_tell" => Function::new_native_with_env(store, thread.clone(), fd_tell), + "fd_write" => Function::new_native_with_env(store, thread.clone(), fd_write), + "fd_pipe" => Function::new_native_with_env(store, thread.clone(), fd_pipe), + "path_create_directory" => Function::new_native_with_env(store, thread.clone(), path_create_directory), + "path_filestat_get" => Function::new_native_with_env(store, thread.clone(), path_filestat_get), + "path_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), path_filestat_set_times), + "path_link" => Function::new_native_with_env(store, thread.clone(), path_link), + "path_open" => Function::new_native_with_env(store, thread.clone(), path_open), + "path_readlink" => Function::new_native_with_env(store, thread.clone(), path_readlink), + "path_remove_directory" => Function::new_native_with_env(store, thread.clone(), path_remove_directory), + "path_rename" => Function::new_native_with_env(store, thread.clone(), path_rename), + "path_symlink" => Function::new_native_with_env(store, thread.clone(), path_symlink), + "path_unlink_file" => Function::new_native_with_env(store, thread.clone(), path_unlink_file), + "poll_oneoff" => Function::new_native_with_env(store, thread.clone(), poll_oneoff), + "proc_exit" => Function::new_native_with_env(store, thread.clone(), proc_exit), + "proc_raise" => Function::new_native_with_env(store, thread.clone(), proc_raise), + "random_get" => Function::new_native_with_env(store, thread.clone(), random_get), + "tty_get" => Function::new_native_with_env(store, thread.clone(), tty_get), + "tty_set" => Function::new_native_with_env(store, thread.clone(), tty_set), + "getcwd" => Function::new_native_with_env(store, thread.clone(), getcwd), + "chdir" => Function::new_native_with_env(store, thread.clone(), chdir), + "thread_spawn" => Function::new_native_with_env(store, thread.clone(), thread_spawn), + "thread_sleep" => Function::new_native_with_env(store, thread.clone(), thread_sleep), + "thread_id" => Function::new_native_with_env(store, thread.clone(), thread_id), + "thread_join" => Function::new_native_with_env(store, thread.clone(), thread_join), + "thread_parallelism" => Function::new_native_with_env(store, thread.clone(), thread_parallelism), + "thread_exit" => Function::new_native_with_env(store, thread.clone(), thread_exit), + "sched_yield" => Function::new_native_with_env(store, thread.clone(), sched_yield), + "getpid" => Function::new_native_with_env(store, thread.clone(), getpid), + "bus_spawn_local" => Function::new_native_with_env(store, thread.clone(), bus_spawn_local), + "bus_spawn_remote" => Function::new_native_with_env(store, thread.clone(), bus_spawn_remote), + "bus_close" => Function::new_native_with_env(store, thread.clone(), bus_close), + "bus_invoke" => Function::new_native_with_env(store, thread.clone(), bus_invoke), + "bus_fault" => Function::new_native_with_env(store, thread.clone(), bus_fault), + "bus_drop" => Function::new_native_with_env(store, thread.clone(), bus_drop), + "bus_reply" => Function::new_native_with_env(store, thread.clone(), bus_reply), + "bus_callback" => Function::new_native_with_env(store, thread.clone(), bus_callback), + "bus_listen" => Function::new_native_with_env(store, thread.clone(), bus_listen), + "bus_poll" => Function::new_native_with_env(store, thread.clone(), bus_poll), + "bus_poll_data" => Function::new_native_with_env(store, thread.clone(), bus_poll_data), + "ws_connect" => Function::new_native_with_env(store, thread.clone(), ws_connect), + "http_request" => Function::new_native_with_env(store, thread.clone(), http_request), + "http_status" => Function::new_native_with_env(store, thread.clone(), http_status), + "port_bridge" => Function::new_native_with_env(store, thread.clone(), port_bridge), + "port_unbridge" => Function::new_native_with_env(store, thread.clone(), port_unbridge), + "port_dhcp_acquire" => Function::new_native_with_env(store, thread.clone(), port_dhcp_acquire), + "port_addr_add" => Function::new_native_with_env(store, thread.clone(), port_addr_add), + "port_addr_remove" => Function::new_native_with_env(store, thread.clone(), port_addr_remove), + "port_addr_clear" => Function::new_native_with_env(store, thread.clone(), port_addr_clear), + "port_addr_list" => Function::new_native_with_env(store, thread.clone(), port_addr_list), + "port_mac" => Function::new_native_with_env(store, thread.clone(), port_mac), + "port_gateway_set" => Function::new_native_with_env(store, thread.clone(), port_gateway_set), + "port_route_add" => Function::new_native_with_env(store, thread.clone(), port_route_add), + "port_route_remove" => Function::new_native_with_env(store, thread.clone(), port_route_remove), + "port_route_clear" => Function::new_native_with_env(store, thread.clone(), port_route_clear), + "port_route_list" => Function::new_native_with_env(store, thread.clone(), port_route_list), + "sock_status" => Function::new_native_with_env(store, thread.clone(), sock_status), + "sock_addr_local" => Function::new_native_with_env(store, thread.clone(), sock_addr_local), + "sock_addr_peer" => Function::new_native_with_env(store, thread.clone(), sock_addr_peer), + "sock_open" => Function::new_native_with_env(store, thread.clone(), sock_open), + "sock_set_opt_flag" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_flag), + "sock_get_opt_flag" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_flag), + "sock_set_opt_time" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_time), + "sock_get_opt_time" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_time), + "sock_set_opt_size" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_size), + "sock_get_opt_size" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_size), + "sock_join_multicast_v4" => Function::new_native_with_env(store, thread.clone(), sock_join_multicast_v4), + "sock_leave_multicast_v4" => Function::new_native_with_env(store, thread.clone(), sock_leave_multicast_v4), + "sock_join_multicast_v6" => Function::new_native_with_env(store, thread.clone(), sock_join_multicast_v6), + "sock_leave_multicast_v6" => Function::new_native_with_env(store, thread.clone(), sock_leave_multicast_v6), + "sock_bind" => Function::new_native_with_env(store, thread.clone(), sock_bind), + "sock_listen" => Function::new_native_with_env(store, thread.clone(), sock_listen), + "sock_accept" => Function::new_native_with_env(store, thread.clone(), sock_accept), + "sock_connect" => Function::new_native_with_env(store, thread.clone(), sock_connect), + "sock_recv" => Function::new_native_with_env(store, thread.clone(), sock_recv), + "sock_recv_from" => Function::new_native_with_env(store, thread.clone(), sock_recv_from), + "sock_send" => Function::new_native_with_env(store, thread.clone(), sock_send), + "sock_send_to" => Function::new_native_with_env(store, thread.clone(), sock_send_to), + "sock_send_file" => Function::new_native_with_env(store, thread.clone(), sock_send_file), + "sock_shutdown" => Function::new_native_with_env(store, thread.clone(), sock_shutdown), + "resolve" => Function::new_native_with_env(store, thread.clone(), resolve), + } + } +} + +fn generate_import_object_wasix64_v1(store: &Store, thread: WasiThread) -> Imports { + use self::wasix64::*; + imports! { + "wasix_64v1" => { + "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), + "args_sizes_get" => Function::new_native_with_env(store, thread.clone(), args_sizes_get), + "clock_res_get" => Function::new_native_with_env(store, thread.clone(), clock_res_get), + "clock_time_get" => Function::new_native_with_env(store, thread.clone(), clock_time_get), + "environ_get" => Function::new_native_with_env(store, thread.clone(), environ_get), + "environ_sizes_get" => Function::new_native_with_env(store, thread.clone(), environ_sizes_get), + "fd_advise" => Function::new_native_with_env(store, thread.clone(), fd_advise), + "fd_allocate" => Function::new_native_with_env(store, thread.clone(), fd_allocate), + "fd_close" => Function::new_native_with_env(store, thread.clone(), fd_close), + "fd_datasync" => Function::new_native_with_env(store, thread.clone(), fd_datasync), + "fd_fdstat_get" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_get), + "fd_fdstat_set_flags" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native_with_env(store, thread.clone(), fd_filestat_get), + "fd_filestat_set_size" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_times), + "fd_pread" => Function::new_native_with_env(store, thread.clone(), fd_pread), + "fd_prestat_get" => Function::new_native_with_env(store, thread.clone(), fd_prestat_get), + "fd_prestat_dir_name" => Function::new_native_with_env(store, thread.clone(), fd_prestat_dir_name), + "fd_pwrite" => Function::new_native_with_env(store, thread.clone(), fd_pwrite), + "fd_read" => Function::new_native_with_env(store, thread.clone(), fd_read), + "fd_readdir" => Function::new_native_with_env(store, thread.clone(), fd_readdir), + "fd_renumber" => Function::new_native_with_env(store, thread.clone(), fd_renumber), + "fd_dup" => Function::new_native_with_env(store, thread.clone(), fd_dup), + "fd_event" => Function::new_native_with_env(store, thread.clone(), fd_event), + "fd_seek" => Function::new_native_with_env(store, thread.clone(), fd_seek), + "fd_sync" => Function::new_native_with_env(store, thread.clone(), fd_sync), + "fd_tell" => Function::new_native_with_env(store, thread.clone(), fd_tell), + "fd_write" => Function::new_native_with_env(store, thread.clone(), fd_write), + "fd_pipe" => Function::new_native_with_env(store, thread.clone(), fd_pipe), + "path_create_directory" => Function::new_native_with_env(store, thread.clone(), path_create_directory), + "path_filestat_get" => Function::new_native_with_env(store, thread.clone(), path_filestat_get), + "path_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), path_filestat_set_times), + "path_link" => Function::new_native_with_env(store, thread.clone(), path_link), + "path_open" => Function::new_native_with_env(store, thread.clone(), path_open), + "path_readlink" => Function::new_native_with_env(store, thread.clone(), path_readlink), + "path_remove_directory" => Function::new_native_with_env(store, thread.clone(), path_remove_directory), + "path_rename" => Function::new_native_with_env(store, thread.clone(), path_rename), + "path_symlink" => Function::new_native_with_env(store, thread.clone(), path_symlink), + "path_unlink_file" => Function::new_native_with_env(store, thread.clone(), path_unlink_file), + "poll_oneoff" => Function::new_native_with_env(store, thread.clone(), poll_oneoff), + "proc_exit" => Function::new_native_with_env(store, thread.clone(), proc_exit), + "proc_raise" => Function::new_native_with_env(store, thread.clone(), proc_raise), + "random_get" => Function::new_native_with_env(store, thread.clone(), random_get), + "tty_get" => Function::new_native_with_env(store, thread.clone(), tty_get), + "tty_set" => Function::new_native_with_env(store, thread.clone(), tty_set), + "getcwd" => Function::new_native_with_env(store, thread.clone(), getcwd), + "chdir" => Function::new_native_with_env(store, thread.clone(), chdir), + "thread_spawn" => Function::new_native_with_env(store, thread.clone(), thread_spawn), + "thread_sleep" => Function::new_native_with_env(store, thread.clone(), thread_sleep), + "thread_id" => Function::new_native_with_env(store, thread.clone(), thread_id), + "thread_join" => Function::new_native_with_env(store, thread.clone(), thread_join), + "thread_parallelism" => Function::new_native_with_env(store, thread.clone(), thread_parallelism), + "thread_exit" => Function::new_native_with_env(store, thread.clone(), thread_exit), + "sched_yield" => Function::new_native_with_env(store, thread.clone(), sched_yield), + "getpid" => Function::new_native_with_env(store, thread.clone(), getpid), + "bus_spawn_local" => Function::new_native_with_env(store, thread.clone(), bus_spawn_local), + "bus_spawn_remote" => Function::new_native_with_env(store, thread.clone(), bus_spawn_remote), + "bus_close" => Function::new_native_with_env(store, thread.clone(), bus_close), + "bus_invoke" => Function::new_native_with_env(store, thread.clone(), bus_invoke), + "bus_fault" => Function::new_native_with_env(store, thread.clone(), bus_fault), + "bus_drop" => Function::new_native_with_env(store, thread.clone(), bus_drop), + "bus_reply" => Function::new_native_with_env(store, thread.clone(), bus_reply), + "bus_callback" => Function::new_native_with_env(store, thread.clone(), bus_callback), + "bus_listen" => Function::new_native_with_env(store, thread.clone(), bus_listen), + "bus_poll" => Function::new_native_with_env(store, thread.clone(), bus_poll), + "bus_poll_data" => Function::new_native_with_env(store, thread.clone(), bus_poll_data), + "ws_connect" => Function::new_native_with_env(store, thread.clone(), ws_connect), + "http_request" => Function::new_native_with_env(store, thread.clone(), http_request), + "http_status" => Function::new_native_with_env(store, thread.clone(), http_status), + "port_bridge" => Function::new_native_with_env(store, thread.clone(), port_bridge), + "port_unbridge" => Function::new_native_with_env(store, thread.clone(), port_unbridge), + "port_dhcp_acquire" => Function::new_native_with_env(store, thread.clone(), port_dhcp_acquire), + "port_addr_add" => Function::new_native_with_env(store, thread.clone(), port_addr_add), + "port_addr_remove" => Function::new_native_with_env(store, thread.clone(), port_addr_remove), + "port_addr_clear" => Function::new_native_with_env(store, thread.clone(), port_addr_clear), + "port_addr_list" => Function::new_native_with_env(store, thread.clone(), port_addr_list), + "port_mac" => Function::new_native_with_env(store, thread.clone(), port_mac), + "port_gateway_set" => Function::new_native_with_env(store, thread.clone(), port_gateway_set), + "port_route_add" => Function::new_native_with_env(store, thread.clone(), port_route_add), + "port_route_remove" => Function::new_native_with_env(store, thread.clone(), port_route_remove), + "port_route_clear" => Function::new_native_with_env(store, thread.clone(), port_route_clear), + "port_route_list" => Function::new_native_with_env(store, thread.clone(), port_route_list), + "sock_status" => Function::new_native_with_env(store, thread.clone(), sock_status), + "sock_addr_local" => Function::new_native_with_env(store, thread.clone(), sock_addr_local), + "sock_addr_peer" => Function::new_native_with_env(store, thread.clone(), sock_addr_peer), + "sock_open" => Function::new_native_with_env(store, thread.clone(), sock_open), + "sock_set_opt_flag" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_flag), + "sock_get_opt_flag" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_flag), + "sock_set_opt_time" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_time), + "sock_get_opt_time" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_time), + "sock_set_opt_size" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_size), + "sock_get_opt_size" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_size), + "sock_join_multicast_v4" => Function::new_native_with_env(store, thread.clone(), sock_join_multicast_v4), + "sock_leave_multicast_v4" => Function::new_native_with_env(store, thread.clone(), sock_leave_multicast_v4), + "sock_join_multicast_v6" => Function::new_native_with_env(store, thread.clone(), sock_join_multicast_v6), + "sock_leave_multicast_v6" => Function::new_native_with_env(store, thread.clone(), sock_leave_multicast_v6), + "sock_bind" => Function::new_native_with_env(store, thread.clone(), sock_bind), + "sock_listen" => Function::new_native_with_env(store, thread.clone(), sock_listen), + "sock_accept" => Function::new_native_with_env(store, thread.clone(), sock_accept), + "sock_connect" => Function::new_native_with_env(store, thread.clone(), sock_connect), + "sock_recv" => Function::new_native_with_env(store, thread.clone(), sock_recv), + "sock_recv_from" => Function::new_native_with_env(store, thread.clone(), sock_recv_from), + "sock_send" => Function::new_native_with_env(store, thread.clone(), sock_send), + "sock_send_to" => Function::new_native_with_env(store, thread.clone(), sock_send_to), + "sock_send_file" => Function::new_native_with_env(store, thread.clone(), sock_send_file), + "sock_shutdown" => Function::new_native_with_env(store, thread.clone(), sock_shutdown), + "resolve" => Function::new_native_with_env(store, thread.clone(), resolve), + } + } +} + fn mem_error_to_wasi(err: MemoryAccessError) -> types::__wasi_errno_t { match err { MemoryAccessError::HeapOutOfBounds => types::__WASI_EFAULT, diff --git a/lib/wasi/src/macros.rs b/lib/wasi/src/macros.rs index b7ad74c2893..259fa572ca7 100644 --- a/lib/wasi/src/macros.rs +++ b/lib/wasi/src/macros.rs @@ -11,7 +11,7 @@ macro_rules! wasi_try { val } Err(err) => { - tracing::trace!("wasi::wasi_try::err: {:?}", err); + tracing::debug!("wasi::wasi_try::err: {:?}", err); return err; } } @@ -29,7 +29,7 @@ macro_rules! wasi_try_ok { val } Err(err) => { - tracing::trace!("wasi::wasi_try_ok::err: {:?}", err); + tracing::debug!("wasi::wasi_try_ok::err: {:?}", err); return Ok(err); } } @@ -44,9 +44,9 @@ macro_rules! wasi_try_ok { } Err(err) => { if err == __WASI_EINTR { - $thread.yield_callback()?; + $thread.yield_now()?; } - tracing::trace!("wasi::wasi_try_ok::err: {:?}", err); + tracing::debug!("wasi::wasi_try_ok::err: {:?}", err); return Ok(err); } } diff --git a/lib/wasi/src/runtime.rs b/lib/wasi/src/runtime.rs new file mode 100644 index 00000000000..a8306a2cd61 --- /dev/null +++ b/lib/wasi/src/runtime.rs @@ -0,0 +1,158 @@ +use std::ops::Deref; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::fmt; +use thiserror::Error; +use wasmer_vbus::{VirtualBus, UnsupportedVirtualBus}; +use wasmer_vnet::{VirtualNetworking}; + +use super::WasiError; +use super::WasiThreadId; +use super::types::*; + +#[derive(Error, Debug)] +pub enum WasiThreadError { + #[error("Multithreading is not supported")] + Unsupported, + #[error("The method named is not an exported function")] + MethodNotFound, +} + +impl Into<__wasi_errno_t> +for WasiThreadError +{ + fn into(self) -> __wasi_errno_t { + match self { + WasiThreadError::Unsupported => __WASI_ENOTSUP, + WasiThreadError::MethodNotFound => __WASI_EINVAL + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct WasiTtyState { + pub cols: u32, + pub rows: u32, + pub width: u32, + pub height: u32, + pub stdin_tty: bool, + pub stdout_tty: bool, + pub stderr_tty: bool, + pub echo: bool, + pub line_buffered: bool, +} + +/// Represents an implementation of the WASI runtime - by default everything is +/// unimplemented. +pub trait WasiRuntimeImplementation: fmt::Debug + Sync +{ + /// For WASI runtimes that support it they can implement a message BUS implementation + /// which allows runtimes to pass serialized messages between each other similar to + /// RPC's. BUS implementation can be implemented that communicate across runtimes + /// thus creating a distributed computing architecture. + fn bus<'a>(&'a self) -> &'a (dyn VirtualBus); + + /// Provides access to all the networking related functions such as sockets. + /// By default networking is not implemented. + fn networking<'a>(&'a self) -> &'a (dyn VirtualNetworking); + + /// Generates a new thread ID + fn thread_generate_id(&self) -> WasiThreadId; + + /// Gets the TTY state + fn tty_get(&self) -> WasiTtyState { + WasiTtyState { + rows: 25, + cols: 80, + width: 800, + height: 600, + stdin_tty: false, + stdout_tty: false, + stderr_tty: false, + echo: true, + line_buffered: true, + } + } + + /// Sets the TTY state + fn tty_set(&self, _tty_state: WasiTtyState) { + } + + /// Spawns a new thread by invoking the + fn thread_spawn(&self, _method: &str, _user_data: u64, _reactor: bool) -> Result { + Err(WasiThreadError::Unsupported) + } + + /// Returns the amount of parallelism that is possible on this platform + fn thread_parallelism(&self) -> Result { + Err(WasiThreadError::Unsupported) + } + + // Joins the specified thread with this thread - which effectively waits for it to exit + fn thread_join(&self, _other: WasiThreadId) -> Result<(), WasiThreadError> { + Err(WasiThreadError::Unsupported) + } + + /// Invokes whenever a WASM thread goes idle. In some runtimes (like singlethreaded + /// execution environments) they will need to do asynchronous work whenever the main + /// thread goes idle and this is the place to hook for that. + fn yield_now(&self, _id: WasiThreadId) -> Result<(), WasiError> { + std::thread::yield_now(); + Ok(()) + } + + /// Gets the current process ID + fn getpid(&self) -> Option { + None + } +} + +#[derive(Debug)] +pub struct PlugableRuntimeImplementation +{ + pub bus: Box, + pub networking: Box, + pub thread_id_seed: AtomicU32, +} + +impl PlugableRuntimeImplementation +{ + pub fn set_bus_implementation(&mut self, bus: I) + where I: VirtualBus + Sync + { + self.bus = Box::new(bus) + } + + pub fn set_networking_implementation(&mut self, net: I) + where I: VirtualNetworking + Sync + { + self.networking = Box::new(net) + } +} + +impl Default +for PlugableRuntimeImplementation +{ + fn default() -> Self { + Self { + #[cfg(not(feature = "host-vnet"))] + networking: Box::new(wasmer_vnet::UnsupportedVirtualNetworking::default()), + #[cfg(feature = "host-vnet")] + networking: Box::new(wasmer_wasi_local_networking::LocalNetworking::default()), + bus: Box::new(UnsupportedVirtualBus::default()), + thread_id_seed: Default::default(), + } + } +} + +impl WasiRuntimeImplementation +for PlugableRuntimeImplementation { + fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { + self.bus.deref() + } + fn networking<'a>(&'a self) -> &'a (dyn VirtualNetworking) { + self.networking.deref() + } + fn thread_generate_id(&self) -> WasiThreadId { + self.thread_id_seed.fetch_add(1, Ordering::Relaxed).into() + } +} diff --git a/lib/wasi/src/state/builder.rs b/lib/wasi/src/state/builder.rs index 773daad4d98..bd0607bdcb4 100644 --- a/lib/wasi/src/state/builder.rs +++ b/lib/wasi/src/state/builder.rs @@ -2,12 +2,12 @@ use crate::state::{default_fs_backing, WasiFs, WasiState}; use crate::syscalls::types::{__WASI_STDERR_FILENO, __WASI_STDIN_FILENO, __WASI_STDOUT_FILENO}; -use crate::{WasiEnv, WasiInodes, WasiThread, WasiError}; +use crate::{WasiEnv, WasiInodes}; use generational_arena::Arena; +use std::sync::Arc; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; -use std::sync::Arc; use std::sync::RwLock; use thiserror::Error; use wasmer_vfs::{FsError, VirtualFile}; @@ -50,7 +50,7 @@ pub struct WasiStateBuilder { stderr_override: Option>, stdin_override: Option>, fs_override: Option>, - on_yield: Option Result<(), WasiError> + Send + Sync + 'static>>, + runtime_override: Option>, } impl std::fmt::Debug for WasiStateBuilder { @@ -61,10 +61,10 @@ impl std::fmt::Debug for WasiStateBuilder { .field("envs", &self.envs) .field("preopens", &self.preopens) .field("setup_fs_fn exists", &self.setup_fs_fn.is_some()) - .field("on_yield exists", &self.on_yield.is_some()) .field("stdout_override exists", &self.stdout_override.is_some()) .field("stderr_override exists", &self.stderr_override.is_some()) .field("stdin_override exists", &self.stdin_override.is_some()) + .field("runtime_override_exists", &self.runtime_override.is_some()) .finish() } } @@ -326,17 +326,12 @@ impl WasiStateBuilder { self } - /// Sets a callback that will be invoked whenever the process yields execution. - /// - /// This is useful if the background tasks and/or callbacks are to be - /// executed whenever the WASM process goes idle - pub fn on_yield(&mut self, callback: F) -> &mut Self - where - F: Fn(&WasiThread) -> Result<(), WasiError>, - F: Send + Sync + 'static, + /// Sets the WASI runtime implementation and overrides the default + /// implementation + pub fn runtime(&mut self, runtime: R) -> &mut Self + where R: crate::WasiRuntimeImplementation + Send + Sync + 'static { - self.on_yield = Some(Arc::new(callback)); - + self.runtime_override = Some(Arc::new(runtime)); self } @@ -499,7 +494,9 @@ impl WasiStateBuilder { let state = self.build()?; let mut env = WasiEnv::new(state); - env.on_yield = self.on_yield.clone(); + if let Some(runtime) = self.runtime_override.as_ref() { + env.runtime = runtime.clone(); + } Ok(env) } } diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index aa8a2d624b6..97da17af7f4 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -17,9 +17,13 @@ mod builder; mod types; +mod socket; +mod pipe; pub use self::builder::*; pub use self::types::*; +pub use self::socket::*; +pub use self::pipe::*; use crate::syscalls::types::*; use crate::utils::map_io_err; use generational_arena::Arena; @@ -27,12 +31,16 @@ pub use generational_arena::Index as Inode; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::collections::VecDeque; +use std::sync::Arc; +use std::sync::mpsc; use std::{ borrow::Borrow, io::Write, ops::{Deref, DerefMut}, path::{Path, PathBuf}, sync::{ + Mutex, atomic::{AtomicU32, AtomicU64, Ordering}, RwLock, RwLockReadGuard, RwLockWriteGuard, }, @@ -139,6 +147,14 @@ pub enum Kind { /// TOOD: clarify here? fd: Option, }, + Socket { + /// Represents a networking socket + socket: InodeSocket, + }, + Pipe { + /// Reference to the pipe + pipe: WasiPipe, + }, Dir { /// Parent directory parent: Option, @@ -172,6 +188,15 @@ pub enum Kind { Buffer { buffer: Vec, }, + EventNotifications { + /// Used for event notifications by the user application or operating system + counter: Arc, + /// Flag that indicates if this is operating + is_semaphore: bool, + /// Receiver that wakes sleeping threads + wakers: Arc>>>, + }, + } #[derive(Debug, Clone)] @@ -338,6 +363,7 @@ pub struct WasiFs { pub fd_map: RwLock>, pub next_fd: AtomicU32, inode_counter: AtomicU64, + pub current_dir: Mutex, #[cfg_attr(feature = "enable-serde", serde(skip, default = "default_fs_backing"))] pub fs_backing: Box, } @@ -585,6 +611,7 @@ impl WasiFs { fd_map: RwLock::new(HashMap::new()), next_fd: AtomicU32::new(3), inode_counter: AtomicU64::new(1024), + current_dir: Mutex::new("/".to_string()), fs_backing, }; wasi_fs.create_stdin(inodes); @@ -828,6 +855,36 @@ impl WasiFs { } } + /// Changes the current directory + pub fn set_current_dir( + &self, + path: &str + ) { + let mut guard = self.current_dir.lock().unwrap(); + *guard = path.to_string(); + } + + /// Gets the current directory + pub fn get_current_dir( + &self, + inodes: &mut WasiInodes, + ) -> Result<(Inode, String), __wasi_errno_t> { + self.get_current_dir_inner(inodes, 0) + } + + fn get_current_dir_inner( + &self, + inodes: &mut WasiInodes, + symlink_count: u32, + ) -> Result<(Inode, String), __wasi_errno_t> { + let current_dir = { + let guard = self.current_dir.lock().unwrap(); + guard.clone() + }; + let inode = self.get_inode_at_path_inner(inodes, VIRTUAL_ROOT_FD, current_dir.as_str(), symlink_count, true)?; + Ok((inode, current_dir)) + } + /// Internal part of the core path resolution function which implements path /// traversal logic such as resolving relative path segments (such as /// `.` and `..`) and resolving symlinks (while preventing infinite @@ -854,9 +911,19 @@ impl WasiFs { } let path: &Path = Path::new(path); - let mut cur_inode = self.get_fd_inode(base)?; let n_components = path.components().count(); + + // If this is the start of the path search and it starts with the + // current directory marker then we need to resolve the current + // path to the inode before we do the search + if path.components().next().map(|c| c.as_os_str().to_str()).flatten() == Some(".") + && base == VIRTUAL_ROOT_FD // File queries will occur on the root first + && symlink_count == 0 // The resolving of the current path only should happen once and not after symbolic links are followed + { + (cur_inode, _) = self.get_current_dir_inner(inodes, symlink_count + 1)?; + } + // TODO: rights checks 'path_iter: for (i, component) in path.components().enumerate() { // used to terminate symlink resolution properly @@ -882,7 +949,9 @@ impl WasiFs { return Err(__WASI_EACCES); } } - "." => continue 'path_iter, + "." => { + continue 'path_iter + }, _ => (), } // used for full resolution of symlinks @@ -1042,7 +1111,7 @@ impl WasiFs { return Err(__WASI_ENOENT); } } - Kind::File { .. } => { + Kind::File { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { return Err(__WASI_ENOTDIR); } Kind::Symlink { @@ -1443,6 +1512,26 @@ impl WasiFs { Ok(idx) } + pub fn clone_fd( + &self, + fd: __wasi_fd_t, + ) -> Result<__wasi_fd_t, __wasi_errno_t> { + let fd = self.get_fd(fd)?; + let idx = self.next_fd.fetch_add(1, Ordering::AcqRel); + self.fd_map.write().unwrap().insert( + idx, + Fd { + rights: fd.rights, + rights_inheriting: fd.rights_inheriting, + flags: fd.flags, + offset: fd.offset, + open_flags: fd.open_flags, + inode: fd.inode, + }, + ); + Ok(idx) + } + /// Low level function to remove an inode, that is it deletes the WASI FS's /// knowledge of a file. /// @@ -1627,6 +1716,13 @@ impl WasiFs { let mut empty_handle = None; std::mem::swap(handle, &mut empty_handle); } + Kind::Socket { ref mut socket, .. } => { + let mut closed_socket = InodeSocket::new(InodeSocketKind::Closed); + std::mem::swap(socket, &mut closed_socket); + } + Kind::Pipe { ref mut pipe } => { + pipe.close(); + } Kind::Dir { parent, path, .. } => { debug!("Closing dir {:?}", &path); let key = path @@ -1670,6 +1766,7 @@ impl WasiFs { return Err(__WASI_EINVAL); } } + Kind::EventNotifications { .. } => { } Kind::Root { .. } => return Err(__WASI_EACCES), Kind::Symlink { .. } | Kind::Buffer { .. } => return Err(__WASI_EINVAL), } diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs new file mode 100644 index 00000000000..696ad9899d5 --- /dev/null +++ b/lib/wasi/src/state/pipe.rs @@ -0,0 +1,114 @@ +use std::sync::mpsc; +use std::sync::Mutex; +use std::ops::DerefMut; +use std::convert::TryInto; +use std::io::{self, Read}; +use bytes::{Buf, Bytes}; +use wasmer::MemorySize; +use crate::syscalls::types::*; +use wasmer::{Memory, WasmSlice}; +use crate::syscalls::{read_bytes, write_bytes}; + +#[derive(Debug)] +pub struct WasiPipe +{ + /// Sends bytes down the pipe + tx: Mutex>>, + /// Receives bytes from the pipe + rx: Mutex>>, + /// Buffers the last read message from the pipe while its being consumed + read_buffer: Option, +} + +impl WasiPipe +{ + pub fn new() -> (WasiPipe, WasiPipe) + { + let (tx1, rx1) = mpsc::channel(); + let (tx2, rx2) = mpsc::channel(); + + let pipe1 = WasiPipe { + tx: Mutex::new(tx1), + rx: Mutex::new(rx2), + read_buffer: None + }; + + let pipe2 = WasiPipe { + tx: Mutex::new(tx2), + rx: Mutex::new(rx1), + read_buffer: None + }; + + (pipe1, pipe2) + } + + pub fn recv(&mut self, memory: &Memory, iov: WasmSlice<__wasi_iovec_t>) -> Result { + loop { + if let Some(buf) = self.read_buffer.as_mut() { + let buf_len = buf.len(); + if buf_len > 0 { + let reader = buf.as_ref(); + let read = read_bytes(reader, memory, iov) + .map(|_| buf_len as usize)?; + buf.advance(read); + return Ok(read); + } + } + let rx = self.rx.lock().unwrap(); + let data = rx.recv() + .map_err(|_| __WASI_EIO)?; + self.read_buffer.replace(Bytes::from(data)); + } + } + + pub fn send(&mut self, memory: &Memory, iov: WasmSlice<__wasi_ciovec_t>) -> Result { + let buf_len: M::Offset = iov.iter().filter_map(|a| a.read().ok()).map(|a| a.buf_len).sum(); + let buf_len: usize = buf_len.try_into().map_err(|_| __WASI_EINVAL)?; + let mut buf = Vec::with_capacity(buf_len); + write_bytes(&mut buf, memory, iov)?; + let tx = self.tx.lock().unwrap(); + tx.send(buf) + .map_err(|_| __WASI_EIO)?; + Ok(buf_len) + } + + pub fn close(&mut self) { + let (mut null_tx, _) = mpsc::channel(); + let (_, mut null_rx) = mpsc::channel(); + { + let mut guard = self.rx.lock().unwrap(); + std::mem::swap(guard.deref_mut(), &mut null_rx); + } + { + let mut guard = self.tx.lock().unwrap(); + std::mem::swap(guard.deref_mut(), &mut null_tx); + } + self.read_buffer.take(); + } +} + +impl Read +for WasiPipe +{ + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + loop { + if let Some(inner_buf) = self.read_buffer.as_mut() { + let buf_len = inner_buf.len(); + if buf_len > 0 { + let mut reader = inner_buf.as_ref(); + let read = reader.read(buf) + .map(|_| buf_len as usize)?; + inner_buf.advance(read); + return Ok(read); + } + } + let rx = self.rx.lock().unwrap(); + let data = rx.recv() + .map_err(|_| io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the wasi pipe is not connected"), + ))?; + self.read_buffer.replace(Bytes::from(data)); + } + } +} diff --git a/lib/wasi/src/state/socket.rs b/lib/wasi/src/state/socket.rs new file mode 100644 index 00000000000..625f51215ad --- /dev/null +++ b/lib/wasi/src/state/socket.rs @@ -0,0 +1,1387 @@ +use std::sync::Mutex; +use std::time::Duration; +use std::mem::transmute; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::convert::TryInto; +use std::io::{self, Read}; +use bytes::{Buf, Bytes}; +use wasmer_vnet::{ + TimeType, + net_error_into_io_err +}; +use crate::syscalls::types::*; +use wasmer::{Memory, WasmSlice, WasmPtr, MemorySize}; +use wasmer_vnet::{ + IpCidr, + IpRoute, + SocketHttpRequest, + VirtualNetworking, + VirtualWebSocket, + VirtualIcmpSocket, + VirtualRawSocket, + VirtualTcpListener, + VirtualTcpSocket, + VirtualUdpSocket, +}; +use super::types::{ + net_error_into_wasi_err, +}; +use crate::syscalls::{read_bytes, write_bytes}; +#[allow(unused_imports)] +use tracing::{debug, error, warn, info}; + +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + +#[derive(Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum InodeHttpSocketType { + /// Used to feed the bytes into the request itself + Request, + /// Used to receive the bytes from the HTTP server + Response, + /// Used to read the headers from the HTTP server + Headers, +} + +#[derive(Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum InodeSocketKind +{ + PreSocket { + family: __wasi_addressfamily_t, + ty: __wasi_socktype_t, + pt: __wasi_sockproto_t, + addr: Option, + only_v6: bool, + reuse_port: bool, + reuse_addr: bool, + send_buf_size: Option, + recv_buf_size: Option, + send_timeout: Option, + recv_timeout: Option, + connect_timeout: Option, + accept_timeout: Option, + }, + HttpRequest(Mutex, InodeHttpSocketType), + WebSocket(Box), + Icmp(Box), + Raw(Box), + TcpListener(Box), + TcpStream(Box), + UdpSocket(Box), + Closed, +} + +pub enum WasiSocketOption +{ + Noop, + ReusePort, + ReuseAddr, + NoDelay, + DontRoute, + OnlyV6, + Broadcast, + MulticastLoopV4, + MulticastLoopV6, + Promiscuous, + Listening, + LastError, + KeepAlive, + Linger, + OobInline, + RecvBufSize, + SendBufSize, + RecvLowat, + SendLowat, + RecvTimeout, + SendTimeout, + ConnectTimeout, + AcceptTimeout, + Ttl, + MulticastTtlV4, + Type, + Proto, +} + +impl From<__wasi_sockoption_t> +for WasiSocketOption +{ + fn from(opt: __wasi_sockoption_t) -> Self { + use WasiSocketOption::*; + match opt { + __WASI_SOCK_OPTION_NOOP => Noop, + __WASI_SOCK_OPTION_REUSE_PORT => ReusePort, + __WASI_SOCK_OPTION_REUSE_ADDR => ReuseAddr, + __WASI_SOCK_OPTION_NO_DELAY => NoDelay, + __WASI_SOCK_OPTION_DONT_ROUTE => DontRoute, + __WASI_SOCK_OPTION_ONLY_V6 => OnlyV6, + __WASI_SOCK_OPTION_BROADCAST => Broadcast, + __WASI_SOCK_OPTION_MULTICAST_LOOP_V4 => MulticastLoopV4, + __WASI_SOCK_OPTION_MULTICAST_LOOP_V6 => MulticastLoopV6, + __WASI_SOCK_OPTION_PROMISCUOUS => Promiscuous, + __WASI_SOCK_OPTION_LISTENING => Listening, + __WASI_SOCK_OPTION_LAST_ERROR => LastError, + __WASI_SOCK_OPTION_KEEP_ALIVE => KeepAlive, + __WASI_SOCK_OPTION_LINGER => Linger, + __WASI_SOCK_OPTION_OOB_INLINE => OobInline, + __WASI_SOCK_OPTION_RECV_BUF_SIZE => RecvBufSize, + __WASI_SOCK_OPTION_SEND_BUF_SIZE => SendBufSize, + __WASI_SOCK_OPTION_RECV_LOWAT => RecvLowat, + __WASI_SOCK_OPTION_SEND_LOWAT => SendLowat, + __WASI_SOCK_OPTION_RECV_TIMEOUT => RecvTimeout, + __WASI_SOCK_OPTION_SEND_TIMEOUT => SendTimeout, + __WASI_SOCK_OPTION_CONNECT_TIMEOUT => ConnectTimeout, + __WASI_SOCK_OPTION_ACCEPT_TIMEOUT => AcceptTimeout, + __WASI_SOCK_OPTION_TTL => Ttl, + __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => MulticastTtlV4, + __WASI_SOCK_OPTION_TYPE => Type, + __WASI_SOCK_OPTION_PROTO => Proto, + _ => return Noop + } + } +} + +#[derive(Debug)] +pub enum WasiSocketStatus +{ + Opening, + Opened, + Closed, + Failed, +} + +#[derive(Debug)] +pub struct WasiHttpStatus { + pub ok: bool, + pub redirected: bool, + pub size: u64, + pub status: u16, +} + +#[derive(Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct InodeSocket +{ + kind: InodeSocketKind, + read_buffer: Option, + read_addr: Option, +} + +impl InodeSocket +{ + pub fn new(kind: InodeSocketKind) -> InodeSocket { + InodeSocket { + kind, + read_buffer: None, + read_addr: None + } + } + + pub fn bind(&mut self, net: &(dyn VirtualNetworking), set_addr: SocketAddr) -> Result, __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::PreSocket { family, ty, addr, reuse_port, reuse_addr, .. } => + { + match *family { + __WASI_ADDRESS_FAMILY_INET4 => { + if set_addr.is_ipv4() == false { + return Err(__WASI_EINVAL); + } + }, + __WASI_ADDRESS_FAMILY_INET6 => { + if set_addr.is_ipv6() == false { + return Err(__WASI_EINVAL); + } + }, + _ => { + return Err(__WASI_ENOTSUP); + } + } + + addr.replace(set_addr); + let addr = addr.clone().unwrap(); + + Ok( + match *ty { + __WASI_SOCK_TYPE_STREAM => { + // we already set the socket address - next we need a bind or connect so nothing + // more to do at this time + None + }, + __WASI_SOCK_TYPE_DGRAM => { + let socket = net + .bind_udp(addr, *reuse_port, *reuse_addr) + .map_err(net_error_into_wasi_err)?; + Some( + InodeSocket::new(InodeSocketKind::UdpSocket(socket)) + ) + }, + _ => return Err(__WASI_EINVAL) + } + ) + }, + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn listen(&mut self, net: &(dyn VirtualNetworking), _backlog: usize) -> Result, __wasi_errno_t> { + match &self.kind { + InodeSocketKind::PreSocket { ty, addr, only_v6, reuse_port, reuse_addr, accept_timeout, .. } => { + Ok( + match *ty { + __WASI_SOCK_TYPE_STREAM => { + if addr.is_none() { return Err(__WASI_EINVAL); } + let addr = addr.as_ref().unwrap().clone(); + let mut socket = net + .listen_tcp(addr, *only_v6, *reuse_port, *reuse_addr) + .map_err(net_error_into_wasi_err)?; + if let Some(accept_timeout) = accept_timeout { + socket.set_timeout(Some(accept_timeout.clone())) + .map_err(net_error_into_wasi_err)?; + } + Some( + InodeSocket::new(InodeSocketKind::TcpListener(socket)) + ) + }, + _ => return Err(__WASI_ENOTSUP) + } + ) + } + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn accept(&self, _fd_flags: __wasi_fdflags_t) -> Result<(Box, SocketAddr), __wasi_errno_t> { + let (sock, addr) = match &self.kind { + InodeSocketKind::TcpListener(sock) => { + sock.accept().map_err(net_error_into_wasi_err) + }, + InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + }?; + Ok( + (sock, addr) + ) + } + + pub fn accept_timeout(&self, _fd_flags: __wasi_fdflags_t, timeout: Duration) -> Result<(Box, SocketAddr), __wasi_errno_t> { + let (sock, addr) = match &self.kind { + InodeSocketKind::TcpListener(sock) => { + sock.accept_timeout(timeout).map_err(net_error_into_wasi_err) + }, + InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + }?; + Ok( + (sock, addr) + ) + } + + pub fn connect(&mut self, net: &(dyn VirtualNetworking), peer: SocketAddr) -> Result, __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::PreSocket { ty, addr, send_timeout, recv_timeout, connect_timeout, .. } => { + Ok( + match *ty { + __WASI_SOCK_TYPE_STREAM => { + let addr = match addr { + Some(a) => a.clone(), + None => { + let ip = match peer.is_ipv4() { + true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + false => IpAddr::V6(Ipv6Addr::UNSPECIFIED) + }; + SocketAddr::new(ip, 0) + } + }; + let mut socket = net + .connect_tcp(addr, peer, connect_timeout.clone()) + .map_err(net_error_into_wasi_err)?; + if let Some(timeout) = send_timeout { + socket.set_opt_time(TimeType::WriteTimeout, Some(timeout.clone())) + .map_err(net_error_into_wasi_err)?; + } + if let Some(timeout) = recv_timeout { + socket.set_opt_time(TimeType::ReadTimeout, Some(timeout.clone())) + .map_err(net_error_into_wasi_err)?; + } + Some( + InodeSocket::new(InodeSocketKind::TcpStream(socket)) + ) + }, + __WASI_SOCK_TYPE_DGRAM => return Err(__WASI_EINVAL), + _ => return Err(__WASI_ENOTSUP) + } + ) + } + InodeSocketKind::UdpSocket(sock) => { + sock.connect(peer).map_err(net_error_into_wasi_err)?; + Ok(None) + }, + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn status(&self) -> Result { + Ok( + match &self.kind { + InodeSocketKind::PreSocket { .. } => WasiSocketStatus::Opening, + InodeSocketKind::WebSocket(_) => WasiSocketStatus::Opened, + InodeSocketKind::HttpRequest( .. ) => WasiSocketStatus::Opened, + InodeSocketKind::TcpListener(_) => WasiSocketStatus::Opened, + InodeSocketKind::TcpStream(_) => WasiSocketStatus::Opened, + InodeSocketKind::UdpSocket(_) => WasiSocketStatus::Opened, + InodeSocketKind::Closed => WasiSocketStatus::Closed, + _ => WasiSocketStatus::Failed, + } + ) + } + + pub fn http_status(&self) -> Result { + Ok( + match &self.kind { + InodeSocketKind::HttpRequest(http, ..) => { + let http = http.lock().unwrap(); + let guard = http.status.lock().unwrap(); + let status = guard.recv() + .map_err(|_| __WASI_EIO)? + .map_err(net_error_into_wasi_err)?; + WasiHttpStatus { + ok: true, + redirected: status.redirected, + status: status.status, + size: status.size as u64, + } + }, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + } + ) + } + + pub fn addr_local(&self) -> Result { + Ok( + match &self.kind { + InodeSocketKind::PreSocket { family, addr, .. } => { + if let Some(addr) = addr { + addr.clone() + } else { + SocketAddr::new( + match family { + &__WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + &__WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + _ => return Err(__WASI_EINVAL) + }, + 0 + ) + } + }, + InodeSocketKind::Icmp(sock) => { + sock.addr_local() + .map_err(net_error_into_wasi_err)? + }, + InodeSocketKind::TcpListener(sock) => { + sock.addr_local() + .map_err(net_error_into_wasi_err)? + }, + InodeSocketKind::TcpStream(sock) => { + sock.addr_local() + .map_err(net_error_into_wasi_err)? + }, + InodeSocketKind::UdpSocket(sock) => { + sock.addr_local() + .map_err(net_error_into_wasi_err)? + }, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + } + ) + } + + pub fn addr_peer(&self) -> Result { + Ok( + match &self.kind { + InodeSocketKind::PreSocket { family, .. } => { + SocketAddr::new( + match family { + &__WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + &__WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + _ => return Err(__WASI_EINVAL) + }, + 0 + ) + }, + InodeSocketKind::TcpStream(sock) => { + sock.addr_peer() + .map_err(net_error_into_wasi_err)? + }, + InodeSocketKind::UdpSocket(sock) => { + sock.addr_peer() + .map_err(net_error_into_wasi_err)? + .map(|addr| Ok(addr)) + .unwrap_or_else(|| { + sock.addr_local() + .map_err(net_error_into_wasi_err) + .map(|addr| { + SocketAddr::new( + match addr { + SocketAddr::V4(_) => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + SocketAddr::V6(_) => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + }, + 0 + ) + }) + })? + }, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + } + ) + } + + pub fn set_opt_flag(&mut self, option: WasiSocketOption, val: bool) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::PreSocket { only_v6, reuse_port, reuse_addr, .. } => { + match option { + WasiSocketOption::OnlyV6 => *only_v6 = val, + WasiSocketOption::ReusePort => *reuse_port = val, + WasiSocketOption::ReuseAddr => *reuse_addr = val, + _ => return Err(__WASI_EINVAL) + }; + }, + InodeSocketKind::Raw(sock) => { + match option { + WasiSocketOption::Promiscuous => sock.set_promiscuous(val).map_err(net_error_into_wasi_err)?, + _ => return Err(__WASI_EINVAL) + } + }, + InodeSocketKind::TcpStream(sock) => { + match option { + WasiSocketOption::NoDelay => sock.set_nodelay(val).map_err(net_error_into_wasi_err)?, + _ => return Err(__WASI_EINVAL) + } + }, + InodeSocketKind::UdpSocket(sock) => { + match option { + WasiSocketOption::Broadcast => sock.set_broadcast(val).map_err(net_error_into_wasi_err)?, + WasiSocketOption::MulticastLoopV4 => sock.set_multicast_loop_v4(val).map_err(net_error_into_wasi_err)?, + WasiSocketOption::MulticastLoopV6 => sock.set_multicast_loop_v6(val).map_err(net_error_into_wasi_err)?, + _ => return Err(__WASI_EINVAL) + } + }, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + } + Ok(()) + } + + pub fn get_opt_flag(&self, option: WasiSocketOption) -> Result { + Ok( + match &self.kind { + InodeSocketKind::PreSocket { only_v6, reuse_port, reuse_addr, .. } => { + match option { + WasiSocketOption::OnlyV6 => *only_v6, + WasiSocketOption::ReusePort => *reuse_port, + WasiSocketOption::ReuseAddr => *reuse_addr, + _ => return Err(__WASI_EINVAL) + } + }, + InodeSocketKind::Raw(sock) => { + match option { + WasiSocketOption::Promiscuous => sock.promiscuous().map_err(net_error_into_wasi_err)?, + _ => return Err(__WASI_EINVAL) + } + }, + InodeSocketKind::TcpStream(sock) => { + match option { + WasiSocketOption::NoDelay => sock.nodelay().map_err(net_error_into_wasi_err)?, + _ => return Err(__WASI_EINVAL) + } + }, + InodeSocketKind::UdpSocket(sock) => { + match option { + WasiSocketOption::Broadcast => sock.broadcast().map_err(net_error_into_wasi_err)?, + WasiSocketOption::MulticastLoopV4 => sock.multicast_loop_v4().map_err(net_error_into_wasi_err)?, + WasiSocketOption::MulticastLoopV6 => sock.multicast_loop_v6().map_err(net_error_into_wasi_err)?, + _ => return Err(__WASI_EINVAL) + } + }, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + } + ) + } + + pub fn set_send_buf_size(&mut self, size: usize) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::PreSocket { send_buf_size, .. } => { + *send_buf_size = Some(size); + }, + InodeSocketKind::TcpStream(sock) => { + sock.set_send_buf_size(size).map_err(net_error_into_wasi_err)?; + }, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + } + Ok(()) + } + + pub fn send_buf_size(&self) -> Result { + match &self.kind { + InodeSocketKind::PreSocket { send_buf_size, .. } => { + Ok(send_buf_size.clone().unwrap_or_default()) + }, + InodeSocketKind::TcpStream(sock) => { + sock.send_buf_size().map_err(net_error_into_wasi_err) + }, + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn set_recv_buf_size(&mut self, size: usize) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::PreSocket { recv_buf_size, .. } => { + *recv_buf_size = Some(size); + }, + InodeSocketKind::TcpStream(sock) => { + sock.set_recv_buf_size(size).map_err(net_error_into_wasi_err)?; + }, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + } + Ok(()) + } + + pub fn recv_buf_size(&self) -> Result { + match &self.kind { + InodeSocketKind::PreSocket { recv_buf_size, .. } => { + Ok(recv_buf_size.clone().unwrap_or_default()) + }, + InodeSocketKind::TcpStream(sock) => { + sock.recv_buf_size().map_err(net_error_into_wasi_err) + }, + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn set_linger(&mut self, linger: Option) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::TcpStream(sock) => { + sock.set_linger(linger).map_err(net_error_into_wasi_err) + }, + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn linger(&self) -> Result, __wasi_errno_t> { + match &self.kind { + InodeSocketKind::TcpStream(sock) => { + sock.linger().map_err(net_error_into_wasi_err) + }, + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn set_opt_time(&mut self, ty: TimeType, timeout: Option) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::TcpStream(sock) => { + sock.set_opt_time(ty, timeout).map_err(net_error_into_wasi_err) + }, + InodeSocketKind::TcpListener(sock) => { + match ty { + TimeType::AcceptTimeout => sock.set_timeout(timeout).map_err(net_error_into_wasi_err), + _ => Err(__WASI_EINVAL) + } + }, + InodeSocketKind::PreSocket { recv_timeout, send_timeout, connect_timeout, accept_timeout, .. } => { + match ty { + TimeType::ConnectTimeout => { + *connect_timeout = timeout; + Ok(()) + } + TimeType::AcceptTimeout => { + *accept_timeout = timeout; + Ok(()) + } + TimeType::ReadTimeout => { + *recv_timeout = timeout; + Ok(()) + } + TimeType::WriteTimeout => { + *send_timeout = timeout; + Ok(()) + } + _ => Err(__WASI_EIO) + } + }, + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn opt_time(&self, ty: TimeType) -> Result, __wasi_errno_t> { + match &self.kind { + InodeSocketKind::TcpStream(sock) => { + sock.opt_time(ty).map_err(net_error_into_wasi_err) + }, + InodeSocketKind::TcpListener(sock) => { + match ty { + TimeType::AcceptTimeout => sock.timeout().map_err(net_error_into_wasi_err), + _ => Err(__WASI_EINVAL) + } + }, + InodeSocketKind::PreSocket { recv_timeout, send_timeout, connect_timeout, accept_timeout, .. } => { + match ty { + TimeType::ConnectTimeout => Ok(connect_timeout.clone()), + TimeType::AcceptTimeout => Ok(accept_timeout.clone()), + TimeType::ReadTimeout => Ok(recv_timeout.clone()), + TimeType::WriteTimeout => Ok(send_timeout.clone()), + _ => Err(__WASI_EINVAL) + } + }, + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn set_ttl(&mut self, ttl: u32) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::TcpStream(sock) => { + sock.set_ttl(ttl).map_err(net_error_into_wasi_err) + } + InodeSocketKind::UdpSocket(sock) => { + sock.set_ttl(ttl).map_err(net_error_into_wasi_err) + } + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn ttl(&self) -> Result { + match &self.kind { + InodeSocketKind::TcpStream(sock) => { + sock.ttl().map_err(net_error_into_wasi_err) + } + InodeSocketKind::UdpSocket(sock) => { + sock.ttl().map_err(net_error_into_wasi_err) + } + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn set_multicast_ttl_v4(&mut self, ttl: u32) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::UdpSocket(sock) => { + sock.set_multicast_ttl_v4(ttl).map_err(net_error_into_wasi_err) + } + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn multicast_ttl_v4(&self) -> Result { + match &self.kind { + InodeSocketKind::UdpSocket(sock) => { + sock.multicast_ttl_v4().map_err(net_error_into_wasi_err) + } + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn join_multicast_v4(&mut self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::UdpSocket(sock) => { + sock.join_multicast_v4(multiaddr, iface).map_err(net_error_into_wasi_err) + } + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn leave_multicast_v4(&mut self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::UdpSocket(sock) => { + sock.leave_multicast_v4(multiaddr, iface).map_err(net_error_into_wasi_err) + } + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn join_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::UdpSocket(sock) => { + sock.join_multicast_v6(multiaddr, iface).map_err(net_error_into_wasi_err) + } + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn leave_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), __wasi_errno_t> { + match &mut self.kind { + InodeSocketKind::UdpSocket(sock) => { + sock.leave_multicast_v6(multiaddr, iface).map_err(net_error_into_wasi_err) + } + InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + } + } + + pub fn send(&mut self, memory: &Memory, iov: WasmSlice<__wasi_ciovec_t>) -> Result { + let buf_len: M::Offset = iov.iter().filter_map(|a| a.read().ok()).map(|a| a.buf_len).sum(); + let buf_len: usize = buf_len.try_into().map_err(|_| __WASI_EINVAL)?; + let mut buf = Vec::with_capacity(buf_len); + write_bytes(&mut buf, memory, iov)?; + match &mut self.kind { + InodeSocketKind::HttpRequest(sock, ty) => { + let sock = sock.lock().unwrap(); + match ty { + InodeHttpSocketType::Request => { + if sock.request.is_none() { return Err(__WASI_EIO); } + let request = sock.request.as_ref().unwrap(); + request.send(buf).map(|_| buf_len).map_err(|_| __WASI_EIO) + }, + _ => { + return Err(__WASI_EIO); + } + } + }, + InodeSocketKind::WebSocket(sock) => sock.send(Bytes::from(buf)).map(|_| buf_len).map_err(net_error_into_wasi_err), + InodeSocketKind::Raw(sock) => sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err), + InodeSocketKind::TcpStream(sock) => sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err), + InodeSocketKind::UdpSocket(sock) => sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err), + InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + }.map(|_| buf_len) + } + + pub fn send_bytes(&mut self, buf: Bytes) -> Result { + let buf_len = buf.len(); + match &mut self.kind { + InodeSocketKind::HttpRequest(sock, ty) => { + let sock = sock.lock().unwrap(); + match ty { + InodeHttpSocketType::Request => { + if sock.request.is_none() { return Err(__WASI_EIO); } + let request = sock.request.as_ref().unwrap(); + request.send(buf.to_vec()).map(|_| buf_len).map_err(|_| __WASI_EIO) + }, + _ => { + return Err(__WASI_EIO); + } + } + }, + InodeSocketKind::WebSocket(sock) => sock.send(buf).map(|_| buf_len).map_err(net_error_into_wasi_err), + InodeSocketKind::Raw(sock) => sock.send(buf).map_err(net_error_into_wasi_err), + InodeSocketKind::TcpStream(sock) => sock.send(buf).map_err(net_error_into_wasi_err), + InodeSocketKind::UdpSocket(sock) => sock.send(buf).map_err(net_error_into_wasi_err), + InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + }.map(|_| buf_len) + } + + pub fn send_to(&mut self, memory: &Memory, iov: WasmSlice<__wasi_ciovec_t>, addr: WasmPtr<__wasi_addr_port_t, M>) -> Result { + let (addr_ip, addr_port) = read_ip_port(memory, addr)?; + let addr = SocketAddr::new(addr_ip, addr_port); + let buf_len: M::Offset = iov.iter().filter_map(|a| a.read().ok()).map(|a| a.buf_len).sum(); + let buf_len: usize = buf_len.try_into().map_err(|_| __WASI_EINVAL)?; + let mut buf = Vec::with_capacity(buf_len); + write_bytes(&mut buf, memory, iov)?; + match &mut self.kind { + InodeSocketKind::Icmp(sock) => sock.send_to(Bytes::from(buf), addr).map_err(net_error_into_wasi_err), + InodeSocketKind::UdpSocket(sock) => sock.send_to(Bytes::from(buf), addr).map_err(net_error_into_wasi_err), + InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), + InodeSocketKind::Closed => Err(__WASI_EIO), + _ => Err(__WASI_ENOTSUP), + }.map(|_| buf_len) + } + + pub fn recv(&mut self, memory: &Memory, iov: WasmSlice<__wasi_iovec_t>) -> Result { + loop { + if let Some(buf) = self.read_buffer.as_mut() { + let buf_len = buf.len(); + if buf_len > 0 { + let reader = buf.as_ref(); + let read = read_bytes(reader, memory, iov) + .map(|_| buf_len)?; + if let InodeSocketKind::TcpStream(..) = &self.kind { + buf.advance(read); + } else { + buf.clear(); + } + return Ok(read); + } + } + let data = match &mut self.kind { + InodeSocketKind::HttpRequest(sock, ty) => { + let sock = sock.lock().unwrap(); + match ty { + InodeHttpSocketType::Response => { + if sock.response.is_none() { return Err(__WASI_EIO); } + let response = sock.response.as_ref().unwrap(); + Bytes::from(response.recv().map_err(|_| __WASI_EIO)?) + }, + InodeHttpSocketType::Headers => { + if sock.headers.is_none() { return Err(__WASI_EIO); } + let headers = sock.headers.as_ref().unwrap(); + let headers = headers.recv().map_err(|_| __WASI_EIO)?; + let headers = format!("{}: {}", headers.0, headers.1); + Bytes::from(headers.as_bytes().to_vec()) + }, + _ => { + return Err(__WASI_EIO); + } + } + }, + InodeSocketKind::WebSocket(sock) => { + let read = sock.recv().map_err(net_error_into_wasi_err)?; + read.data + }, + InodeSocketKind::Raw(sock) => { + let read = sock.recv().map_err(net_error_into_wasi_err)?; + read.data + }, + InodeSocketKind::TcpStream(sock) => { + let read = sock.recv().map_err(net_error_into_wasi_err)?; + read.data + }, + InodeSocketKind::UdpSocket(sock) => { + let read = sock.recv().map_err(net_error_into_wasi_err)?; + read.data + }, + InodeSocketKind::PreSocket { .. } => return Err(__WASI_ENOTCONN), + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + }; + self.read_buffer.replace(data); + self.read_addr.take(); + } + } + + pub fn recv_from(&mut self, memory: &Memory, iov: WasmSlice<__wasi_iovec_t>, addr: WasmPtr<__wasi_addr_port_t, M>) -> Result { + loop { + if let Some(buf) = self.read_buffer.as_mut() { + if buf.len() > 0 { + let reader = buf.as_ref(); + let ret = read_bytes(reader, memory, iov)?; + let peer = self.read_addr.clone().unwrap_or_else(|| SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)); + write_ip_port(memory, addr, peer.ip(), peer.port())?; + return Ok(ret); + } + } + let rcv = match &mut self.kind { + InodeSocketKind::Icmp(sock) => { + sock.recv_from().map_err(net_error_into_wasi_err)? + }, + InodeSocketKind::UdpSocket(sock) => { + sock.recv_from().map_err(net_error_into_wasi_err)? + }, + InodeSocketKind::PreSocket { .. } => return Err(__WASI_ENOTCONN), + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + }; + self.read_buffer.replace(rcv.data); + self.read_addr.replace(rcv.addr); + } + } + + pub fn shutdown(&mut self, how: std::net::Shutdown) -> Result<(), __wasi_errno_t> { + use std::net::Shutdown; + match &mut self.kind { + InodeSocketKind::TcpStream(sock) => { + sock.shutdown(how).map_err(net_error_into_wasi_err)?; + }, + InodeSocketKind::HttpRequest(http, ..) => { + let mut http = http.lock().unwrap(); + match how { + Shutdown::Read => { + http.response.take(); + http.headers.take(); + }, + Shutdown::Write => { + http.request.take(); + }, + Shutdown::Both => { + http.request.take(); + http.response.take(); + http.headers.take(); + }, + }; + }, + InodeSocketKind::PreSocket { .. } => return Err(__WASI_ENOTCONN), + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + } + Ok(()) + } +} + +impl Read +for InodeSocket +{ + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + loop { + if let Some(read_buf) = self.read_buffer.as_mut() { + let buf_len = read_buf.len(); + if buf_len > 0 { + let mut reader = read_buf.as_ref(); + let read = reader.read(buf)?; + read_buf.advance(read); + return Ok(read); + } + } + let data = match &mut self.kind { + InodeSocketKind::HttpRequest(sock, ty) => { + let sock = sock.lock().unwrap(); + match ty { + InodeHttpSocketType::Response => { + if sock.response.is_none() { return Err(io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the socket is not connected"), + )); } + let response = sock.response.as_ref().unwrap(); + Bytes::from(response.recv().map_err(|_| io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the wasi pipe is not connected"), + ))?) + }, + InodeHttpSocketType::Headers => { + if sock.headers.is_none() { return Err(io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the socket is not connected"), + )); } + let headers = sock.headers.as_ref().unwrap(); + let headers = headers.recv().map_err(|_| io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the wasi pipe is not connected"), + ))?; + let headers = format!("{}: {}", headers.0, headers.1); + Bytes::from(headers.as_bytes().to_vec()) + }, + _ => { + return Err(io::Error::new( + io::ErrorKind::Unsupported, + format!("the socket is of an unsupported type"), + )); + } + } + }, + InodeSocketKind::WebSocket(sock) => { + let read = sock.recv().map_err(net_error_into_io_err)?; + read.data + }, + InodeSocketKind::Raw(sock) => { + let read = sock.recv().map_err(net_error_into_io_err)?; + read.data + }, + InodeSocketKind::TcpStream(sock) => { + let read = sock.recv().map_err(net_error_into_io_err)?; + read.data + }, + InodeSocketKind::UdpSocket(sock) => { + let read = sock.recv().map_err(net_error_into_io_err)?; + read.data + }, + InodeSocketKind::PreSocket { .. } => return Err(io::Error::new( + io::ErrorKind::NotConnected, + format!("the socket is not connected"), + )), + InodeSocketKind::Closed => return Err(io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the socket has been closed"), + )), + _ => return Err(io::Error::new( + io::ErrorKind::Unsupported, + format!("the socket type is not supported"), + )), + }; + self.read_buffer.replace(data); + self.read_addr.take(); + } + } +} + +impl Drop +for InodeSocket +{ + fn drop(&mut self) { + match &self.kind { + InodeSocketKind::HttpRequest(http, ty) => { + let mut guard = http.lock().unwrap(); + match ty { + InodeHttpSocketType::Request => { + guard.request.take(); + }, + InodeHttpSocketType::Response => { + guard.response.take(); + }, + InodeHttpSocketType::Headers => { + guard.headers.take(); + } + } + }, + _ => { } + } + } +} + +#[allow(dead_code)] +pub(crate) fn read_ip(memory: &Memory, ptr: WasmPtr<__wasi_addr_t, M>) -> Result { + let addr_ptr = ptr.deref(memory); + let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; + + let o = addr.u.octs; + Ok( + match addr.tag { + __WASI_ADDRESS_FAMILY_INET4 => { + IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])) + }, + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(o) }; + IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)) + }, + _ => return Err(__WASI_EINVAL) + } + ) +} + +pub(crate) fn read_ip_v4(memory: &Memory, ptr: WasmPtr<__wasi_addr_ip4_t, M>) -> Result { + let addr_ptr = ptr.deref(memory); + let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; + + let o = addr.octs; + Ok( + Ipv4Addr::new(o[0], o[1], o[2], o[3]) + ) +} + +pub(crate) fn read_ip_v6(memory: &Memory, ptr: WasmPtr<__wasi_addr_ip6_t, M>) -> Result { + let addr_ptr = ptr.deref(memory); + let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; + + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(addr.segs) }; + Ok( + Ipv6Addr::new(a, b, c, d, e, f, g ,h) + ) +} + +pub(crate) fn write_ip(memory: &Memory, ptr: WasmPtr<__wasi_addr_t, M>, ip: IpAddr) -> Result<(), __wasi_errno_t> { + let ip = match ip { + IpAddr::V4(ip) => { + let o = ip.octets(); + __wasi_addr_t { + tag: __WASI_ADDRESS_FAMILY_INET4, + u: __wasi_addr_u { + octs: [ o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + } + } + }, + IpAddr::V6(ip) => { + let o = ip.octets(); + __wasi_addr_t { + tag: __WASI_ADDRESS_FAMILY_INET6, + u: __wasi_addr_u { + octs: o + } + } + } + }; + + let addr_ptr = ptr.deref(memory); + addr_ptr.write(ip).map_err(crate::mem_error_to_wasi)?; + Ok(()) +} + +#[allow(dead_code)] +pub(crate) fn read_cidr(memory: &Memory, ptr: WasmPtr<__wasi_cidr_t, M>) -> Result { + let addr_ptr = ptr.deref(memory); + let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; + + let o = addr.u.octs; + Ok( + match addr.tag { + __WASI_ADDRESS_FAMILY_INET4 => { + IpCidr { + ip: IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])), + prefix: o[4] + } + }, + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = { + let o = [ o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15] ]; + unsafe { transmute::<_, [u16; 8]>(o) } + }; + IpCidr { + ip: IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)), + prefix: o[16] + } + }, + _ => return Err(__WASI_EINVAL) + } + ) +} + +#[allow(dead_code)] +pub(crate) fn write_cidr(memory: &Memory, ptr: WasmPtr<__wasi_cidr_t, M>, cidr: IpCidr) -> Result<(), __wasi_errno_t> { + let p = cidr.prefix; + let cidr = match cidr.ip { + IpAddr::V4(ip) => { + let o = ip.octets(); + __wasi_cidr_t { + tag: __WASI_ADDRESS_FAMILY_INET4, + u: __wasi_cidr_u { + octs: [ o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + } + } + }, + IpAddr::V6(ip) => { + let o = ip.octets(); + __wasi_cidr_t { + tag: __WASI_ADDRESS_FAMILY_INET6, + u: __wasi_cidr_u { + octs: [ o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15], p ] + } + } + } + }; + + let addr_ptr = ptr.deref(memory); + addr_ptr.write(cidr).map_err(crate::mem_error_to_wasi)?; + Ok(()) +} + +pub(crate) fn read_ip_port(memory: &Memory, ptr: WasmPtr<__wasi_addr_port_t, M>) -> Result<(IpAddr, u16), __wasi_errno_t> { + let addr_ptr = ptr.deref(memory); + let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; + + let o = addr.u.octs; + Ok( + match addr.tag { + __WASI_ADDRESS_FAMILY_INET4 => { + let port = u16::from_ne_bytes([ o[0], o[1] ]); + ( + IpAddr::V4(Ipv4Addr::new(o[2], o[3], o[4], o[5])), + port + ) + }, + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = { + let o = [ o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15], o[16], o[17] ]; + unsafe { transmute::<_, [u16; 8]>(o) } + }; + ( + IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)), + u16::from_ne_bytes([ o[0], o[1] ]) + ) + }, + _ => return Err(__WASI_EINVAL) + } + ) +} + +#[allow(dead_code)] +pub(crate) fn write_ip_port(memory: &Memory, ptr: WasmPtr<__wasi_addr_port_t, M>, ip: IpAddr, port: u16) -> Result<(), __wasi_errno_t> { + let p = port.to_be_bytes(); + let ipport = match ip { + IpAddr::V4(ip) => { + let o = ip.octets(); + __wasi_addr_port_t { + tag: __WASI_ADDRESS_FAMILY_INET4, + u: __wasi_addr_port_u { + octs: [ p[0], p[1], o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + } + } + }, + IpAddr::V6(ip) => { + let o = ip.octets(); + __wasi_addr_port_t { + tag: __WASI_ADDRESS_FAMILY_INET6, + u: __wasi_addr_port_u { + octs: [ p[0], p[1], o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15] ] + } + } + } + }; + + let addr_ptr = ptr.deref(memory); + addr_ptr.write(ipport).map_err(crate::mem_error_to_wasi)?; + Ok(()) +} + +#[allow(dead_code)] +pub(crate) fn read_route(memory: &Memory, ptr: WasmPtr<__wasi_route_t, M>) -> Result { + let route_ptr = ptr.deref(memory); + let route = route_ptr.read().map_err(crate::mem_error_to_wasi)?; + + Ok( + IpRoute { + cidr: { + let o = route.cidr.u.octs; + match route.cidr.tag { + __WASI_ADDRESS_FAMILY_INET4 => { + IpCidr { + ip: IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])), + prefix: o[4] + } + }, + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = { + let o = [ o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15] ]; + unsafe { transmute::<_, [u16; 8]>(o) } + }; + IpCidr { + ip: IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)), + prefix: o[16] + } + }, + _ => return Err(__WASI_EINVAL) + } + }, + via_router: { + let o = route.via_router.u.octs; + match route.via_router.tag { + __WASI_ADDRESS_FAMILY_INET4 => { + IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])) + }, + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(o) }; + IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)) + }, + _ => return Err(__WASI_EINVAL) + } + }, + preferred_until: match route.preferred_until.tag { + __WASI_OPTION_NONE => None, + __WASI_OPTION_SOME => Some( + Duration::from_nanos(route.preferred_until.u) + ), + _ => return Err(__WASI_EINVAL) + }, + expires_at: match route.expires_at.tag { + __WASI_OPTION_NONE => None, + __WASI_OPTION_SOME => Some( + Duration::from_nanos(route.expires_at.u) + ), + _ => return Err(__WASI_EINVAL) + } + } + ) +} + +pub(crate) fn write_route(memory: &Memory, ptr: WasmPtr<__wasi_route_t, M>, route: IpRoute) -> Result<(), __wasi_errno_t> { + let cidr = { + let p = route.cidr.prefix; + match route.cidr.ip { + IpAddr::V4(ip) => { + let o = ip.octets(); + __wasi_cidr_t { + tag: __WASI_ADDRESS_FAMILY_INET4, + u: __wasi_cidr_u { + octs: [ o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + } + } + }, + IpAddr::V6(ip) => { + let o = ip.octets(); + __wasi_cidr_t { + tag: __WASI_ADDRESS_FAMILY_INET6, + u: __wasi_cidr_u { + octs: [ o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15], p ] + } + } + } + } + }; + let via_router = match route.via_router { + IpAddr::V4(ip) => { + let o = ip.octets(); + __wasi_addr_t { + tag: __WASI_ADDRESS_FAMILY_INET4, + u: __wasi_addr_u { + octs: [ o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + } + } + }, + IpAddr::V6(ip) => { + let o = ip.octets(); + __wasi_addr_t { + tag: __WASI_ADDRESS_FAMILY_INET6, + u: __wasi_addr_u { + octs: o + } + } + } + }; + let preferred_until = match route.preferred_until { + None => __wasi_option_timestamp_t { + tag: __WASI_OPTION_NONE, + u: 0 + }, + Some(u) => __wasi_option_timestamp_t { + tag: __WASI_OPTION_SOME, + u: u.as_nanos() as u64 + } + }; + let expires_at = match route.expires_at { + None => __wasi_option_timestamp_t { + tag: __WASI_OPTION_NONE, + u: 0 + }, + Some(u) => __wasi_option_timestamp_t { + tag: __WASI_OPTION_SOME, + u: u.as_nanos() as u64 + } + }; + + let route = __wasi_route_t { + cidr, + via_router, + preferred_until, + expires_at + }; + + let route_ptr = ptr.deref(memory); + route_ptr.write(route).map_err(crate::mem_error_to_wasi)?; + Ok(()) +} + +pub(crate) fn all_socket_rights() -> __wasi_rights_t { + __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | + __WASI_RIGHT_FD_FILESTAT_GET | + __WASI_RIGHT_FD_READ | + __WASI_RIGHT_FD_WRITE | + __WASI_RIGHT_POLL_FD_READWRITE | + __WASI_RIGHT_SOCK_SHUTDOWN | + __WASI_RIGHT_SOCK_CONNECT | + __WASI_RIGHT_SOCK_LISTEN | + __WASI_RIGHT_SOCK_BIND | + __WASI_RIGHT_SOCK_ACCEPT | + __WASI_RIGHT_SOCK_RECV | + __WASI_RIGHT_SOCK_SEND | + __WASI_RIGHT_SOCK_ADDR_LOCAL | + __WASI_RIGHT_SOCK_ADDR_REMOTE | + __WASI_RIGHT_SOCK_RECV_FROM | + __WASI_RIGHT_SOCK_SEND_TO +} diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index f14ab1de92b..996e81e3612 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; #[cfg(all(unix, feature = "sys-poll"))] use std::convert::TryInto; use std::{ + sync::{Arc, Mutex}, collections::VecDeque, io::{self, Read, Seek, Write}, time::Duration, @@ -16,6 +17,7 @@ pub use wasmer_vfs::host_fs::{Stderr, Stdin, Stdout}; pub use wasmer_vfs::mem_fs::{Stderr, Stdin, Stdout}; use wasmer_vfs::{FsError, VirtualFile}; +use wasmer_vnet::{NetworkError}; pub fn fs_error_from_wasi_err(err: __wasi_errno_t) -> FsError { match err { @@ -72,6 +74,33 @@ pub fn fs_error_into_wasi_err(fs_error: FsError) -> __wasi_errno_t { } } +pub fn net_error_into_wasi_err(net_error: NetworkError) -> __wasi_errno_t { + match net_error { + NetworkError::InvalidFd => __WASI_EBADF, + NetworkError::AlreadyExists => __WASI_EEXIST, + NetworkError::Lock => __WASI_EIO, + NetworkError::IOError => __WASI_EIO, + NetworkError::AddressInUse => __WASI_EADDRINUSE, + NetworkError::AddressNotAvailable => __WASI_EADDRNOTAVAIL, + NetworkError::BrokenPipe => __WASI_EPIPE, + NetworkError::ConnectionAborted => __WASI_ECONNABORTED, + NetworkError::ConnectionRefused => __WASI_ECONNREFUSED, + NetworkError::ConnectionReset => __WASI_ECONNRESET, + NetworkError::Interrupted => __WASI_EINTR, + NetworkError::InvalidData => __WASI_EIO, + NetworkError::InvalidInput => __WASI_EINVAL, + NetworkError::NotConnected => __WASI_ENOTCONN, + NetworkError::NoDevice => __WASI_ENODEV, + NetworkError::PermissionDenied => __WASI_EPERM, + NetworkError::TimedOut => __WASI_ETIMEDOUT, + NetworkError::UnexpectedEof => __WASI_EPROTO, + NetworkError::WouldBlock => __WASI_EAGAIN, + NetworkError::WriteZero => __WASI_ENOSPC, + NetworkError::Unsupported => __WASI_ENOTSUP, + NetworkError::UnknownError => __WASI_EIO, + } +} + #[derive(Debug, Clone)] #[allow(clippy::enum_variant_names)] pub enum PollEvent { @@ -288,10 +317,10 @@ pub(crate) fn poll( pub trait WasiPath {} /// For piping stdio. Stores all output / input in a byte-vector. -#[derive(Debug, Default)] +#[derive(Debug, Clone, Default)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Pipe { - buffer: VecDeque, + buffer: Arc>>, } impl Pipe { @@ -302,8 +331,9 @@ impl Pipe { impl Read for Pipe { fn read(&mut self, buf: &mut [u8]) -> io::Result { - let amt = std::cmp::min(buf.len(), self.buffer.len()); - for (i, byte) in self.buffer.drain(..amt).enumerate() { + let mut buffer = self.buffer.lock().unwrap(); + let amt = std::cmp::min(buf.len(), buffer.len()); + for (i, byte) in buffer.drain(..amt).enumerate() { buf[i] = byte; } Ok(amt) @@ -312,7 +342,8 @@ impl Read for Pipe { impl Write for Pipe { fn write(&mut self, buf: &[u8]) -> io::Result { - self.buffer.extend(buf); + let mut buffer = self.buffer.lock().unwrap(); + buffer.extend(buf); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { @@ -341,17 +372,20 @@ impl VirtualFile for Pipe { 0 } fn size(&self) -> u64 { - self.buffer.len() as u64 + let buffer = self.buffer.lock().unwrap(); + buffer.len() as u64 } fn set_len(&mut self, len: u64) -> Result<(), FsError> { - self.buffer.resize(len as usize, 0); + let mut buffer = self.buffer.lock().unwrap(); + buffer.resize(len as usize, 0); Ok(()) } fn unlink(&mut self) -> Result<(), FsError> { Ok(()) } - fn bytes_available(&self) -> Result { - Ok(self.buffer.len()) + fn bytes_available_read(&self) -> Result, FsError> { + let buffer = self.buffer.lock().unwrap(); + Ok(Some(buffer.len())) } } diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index f18d9426f95..249876712dd 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -1,6 +1,6 @@ use crate::syscalls; use crate::syscalls::types::{self, snapshot0}; -use crate::{mem_error_to_wasi, WasiEnv, WasiError, WasiThread}; +use crate::{mem_error_to_wasi, WasiEnv, WasiError, WasiThread, MemorySize, Memory32}; use wasmer::WasmPtr; /// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size @@ -12,21 +12,21 @@ use wasmer::WasmPtr; pub fn fd_filestat_get( thread: &WasiThread, fd: types::__wasi_fd_t, - buf: WasmPtr, + buf: WasmPtr, ) -> types::__wasi_errno_t { let memory = thread.memory(); // transmute the WasmPtr into a WasmPtr where T2 > T1, this will read extra memory. // The edge case of this cenv.mausing an OOB is not handled, if the new field is OOB, then the entire // memory access will fail. - let new_buf: WasmPtr = buf.cast(); + let new_buf: WasmPtr = buf.cast(); // Copy the data including the extra data let new_filestat_setup: types::__wasi_filestat_t = wasi_try_mem!(new_buf.read(memory)); // Set up complete, make the call with the pointer that will write to the // struct and some unrelated memory after the struct. - let result = syscalls::fd_filestat_get(thread, fd, new_buf); + let result = syscalls::fd_filestat_get::(thread, fd, new_buf); // reborrow memory let memory = thread.memory(); @@ -62,17 +62,17 @@ pub fn path_filestat_get( thread: &WasiThread, fd: types::__wasi_fd_t, flags: types::__wasi_lookupflags_t, - path: WasmPtr, + path: WasmPtr, path_len: u32, - buf: WasmPtr, + buf: WasmPtr, ) -> types::__wasi_errno_t { // see `fd_filestat_get` in this file for an explanation of this strange behavior let memory = thread.memory(); - let new_buf: WasmPtr = buf.cast(); + let new_buf: WasmPtr = buf.cast(); let new_filestat_setup: types::__wasi_filestat_t = wasi_try_mem!(new_buf.read(memory)); - let result = syscalls::path_filestat_get(thread, fd, flags, path, path_len, new_buf); + let result = syscalls::path_filestat_get::(thread, fd, flags, path, path_len, new_buf); let memory = thread.memory(); let new_filestat = wasi_try_mem!(new_buf.deref(memory).read()); @@ -100,7 +100,7 @@ pub fn fd_seek( fd: types::__wasi_fd_t, offset: types::__wasi_filedelta_t, whence: snapshot0::__wasi_whence_t, - newoffset: WasmPtr, + newoffset: WasmPtr, ) -> Result { let new_whence = match whence { snapshot0::__WASI_WHENCE_CUR => types::__WASI_WHENCE_CUR, @@ -109,30 +109,31 @@ pub fn fd_seek( // if it's invalid, let the new fd_seek handle it _ => whence, }; - syscalls::fd_seek(thread, fd, offset, new_whence, newoffset) + syscalls::fd_seek::(thread, fd, offset, new_whence, newoffset) } /// Wrapper around `syscalls::poll_oneoff` with extra logic to add the removed /// userdata field back pub fn poll_oneoff( thread: &WasiThread, - in_: WasmPtr, - out_: WasmPtr, + in_: WasmPtr, + out_: WasmPtr, nsubscriptions: u32, - nevents: WasmPtr, + nevents: WasmPtr, ) -> Result { // in this case the new type is smaller than the old type, so it all fits into memory, // we just need to readjust and copy it // we start by adjusting `in_` into a format that the new code can understand let memory = thread.memory(); - let in_origs = wasi_try_mem_ok!(in_.slice(memory, nsubscriptions)); + let nsubscriptions_offset: u32 = nsubscriptions.into(); + let in_origs = wasi_try_mem_ok!(in_.slice(memory, nsubscriptions_offset)); let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); // get a pointer to the smaller new type - let in_new_type_ptr: WasmPtr = in_.cast(); + let in_new_type_ptr: WasmPtr = in_.cast(); - for (in_sub_new, orig) in wasi_try_mem_ok!(in_new_type_ptr.slice(memory, nsubscriptions)) + for (in_sub_new, orig) in wasi_try_mem_ok!(in_new_type_ptr.slice(memory, nsubscriptions_offset)) .iter() .zip(in_origs.iter()) { @@ -157,12 +158,12 @@ pub fn poll_oneoff( } // make the call - let result = syscalls::poll_oneoff(thread, in_new_type_ptr, out_, nsubscriptions, nevents); + let result = syscalls::poll_oneoff::(thread, in_new_type_ptr, out_, nsubscriptions, nevents); // replace the old values of in, in case the calling code reuses the memory let memory = thread.memory(); - for (in_sub, orig) in wasi_try_mem_ok!(in_.slice(memory, nsubscriptions)) + for (in_sub, orig) in wasi_try_mem_ok!(in_.slice(memory, nsubscriptions_offset)) .iter() .zip(in_origs.into_iter()) { diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index d2f7ded0231..979bb646d2a 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -17,27 +17,38 @@ pub mod wasm32; pub mod windows; pub mod legacy; +pub mod wasi; +pub mod wasix32; +pub mod wasix64; use self::types::*; +use crate::state::InodeHttpSocketType; use crate::utils::map_io_err; use crate::{ mem_error_to_wasi, state::{ - self, fs_error_into_wasi_err, iterate_poll_events, poll, + self, fs_error_into_wasi_err, net_error_into_wasi_err, iterate_poll_events, poll, virtual_file_type_to_wasi_file_type, Fd, Inode, InodeVal, Kind, PollEvent, - PollEventBuilder, WasiState, MAX_SYMLINKS, + PollEventBuilder, WasiState, MAX_SYMLINKS, InodeSocket, InodeSocketKind, + WasiPipe, }, - WasiEnv, WasiError, WasiThread, + WasiEnv, WasiError, WasiThread, WasiThreadId }; use std::borrow::Borrow; use std::convert::{Infallible, TryInto}; use std::io::{self, Read, Seek, Write}; +use std::sync::{Arc, mpsc}; +use std::sync::atomic::AtomicU64; use std::time::Duration; use std::ops::{Deref, DerefMut}; -use std::sync::atomic::Ordering; -use tracing::{debug, trace}; -use wasmer::{Memory, RuntimeError, Value, WasmPtr, WasmSlice}; +use std::sync::{Mutex, atomic::Ordering}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::mem::transmute; +use bytes::Bytes; +use tracing::{debug, trace, error}; +use wasmer::{Memory, RuntimeError, Value, WasmPtr, WasmSlice, MemorySize, Memory32, Memory64}; use wasmer_vfs::{FsError, VirtualFile}; +use wasmer_vnet::{StreamSecurity, SocketHttpRequest}; #[cfg(any( target_os = "freebsd", @@ -53,41 +64,53 @@ pub use windows::*; #[cfg(any(target_arch = "wasm32"))] pub use wasm32::*; -fn write_bytes_inner( +fn to_offset(offset: usize) -> Result +{ + let ret: M::Offset = offset.try_into().map_err(|_| __WASI_EINVAL)?; + Ok(ret) +} + +fn from_offset(offset: M::Offset) -> Result +{ + let ret: usize = offset.try_into().map_err(|_| __WASI_EINVAL)?; + Ok(ret) +} + +fn write_bytes_inner( mut write_loc: T, memory: &Memory, - iovs_arr_cell: WasmSlice<__wasi_ciovec_t>, -) -> Result { - let mut bytes_written = 0; + iovs_arr_cell: WasmSlice<__wasi_ciovec_t>, +) -> Result { + let mut bytes_written = 0usize; for iov in iovs_arr_cell.iter() { let iov_inner = iov.read().map_err(mem_error_to_wasi)?; - let bytes = WasmPtr::::new(iov_inner.buf) + let bytes = WasmPtr::::new(iov_inner.buf) .slice(memory, iov_inner.buf_len) .map_err(mem_error_to_wasi)?; let bytes = bytes.read_to_vec().map_err(mem_error_to_wasi)?; write_loc.write_all(&bytes).map_err(map_io_err)?; - bytes_written += iov_inner.buf_len; + bytes_written += from_offset::(iov_inner.buf_len)?; } Ok(bytes_written) } -fn write_bytes( +pub(crate) fn write_bytes( mut write_loc: T, memory: &Memory, - iovs_arr: WasmSlice<__wasi_ciovec_t>, -) -> Result { - let result = write_bytes_inner(&mut write_loc, memory, iovs_arr); + iovs_arr: WasmSlice<__wasi_ciovec_t>, +) -> Result { + let result = write_bytes_inner::<_, M>(&mut write_loc, memory, iovs_arr); write_loc.flush(); result } -fn read_bytes( +pub(crate) fn read_bytes( mut reader: T, memory: &Memory, - iovs_arr: WasmSlice<__wasi_iovec_t>, -) -> Result { - let mut bytes_read = 0; + iovs_arr: WasmSlice<__wasi_iovec_t>, +) -> Result { + let mut bytes_read = 0usize; // We allocate the raw_bytes first once instead of // N times in the loop. @@ -96,10 +119,10 @@ fn read_bytes( for iov in iovs_arr.iter() { let iov_inner = iov.read().map_err(mem_error_to_wasi)?; raw_bytes.clear(); - raw_bytes.resize(iov_inner.buf_len as usize, 0); - bytes_read += reader.read(&mut raw_bytes).map_err(map_io_err)? as u32; + raw_bytes.resize(from_offset::(iov_inner.buf_len)?, 0); + bytes_read += reader.read(&mut raw_bytes).map_err(map_io_err)?; - let buf = WasmPtr::::new(iov_inner.buf) + let buf = WasmPtr::::new(iov_inner.buf) .slice(memory, iov_inner.buf_len) .map_err(mem_error_to_wasi)?; buf.write_slice(&raw_bytes).map_err(mem_error_to_wasi)?; @@ -112,26 +135,135 @@ fn has_rights(rights_set: __wasi_rights_t, rights_check_set: __wasi_rights_t) -> rights_set | rights_check_set == rights_set } +fn __sock_actor( + thread: &WasiThread, + sock: __wasi_fd_t, + rights: __wasi_rights_t, + actor: F +) -> Result +where F: FnOnce(&crate::state::InodeSocket) -> Result +{ + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + + let fd_entry = state.fs.get_fd(sock)?; + let ret = { + if rights != 0 { + if !has_rights(fd_entry.rights, rights) { + return Err(__WASI_EACCES); + } + } + + let inode_idx = fd_entry.inode; + let inode = &inodes.arena[inode_idx]; + + let mut guard = inode.read(); + match guard.deref() { + Kind::Socket { socket } => { + actor(socket)? + } + _ => { + return Err(__WASI_ENOTSOCK); + } + } + }; + + Ok(ret) +} + +fn __sock_actor_mut( + thread: &WasiThread, + sock: __wasi_fd_t, + rights: __wasi_rights_t, + actor: F +) -> Result +where F: FnOnce(&mut crate::state::InodeSocket) -> Result +{ + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + + let fd_entry = state.fs.get_fd(sock)?; + let ret = { + if rights != 0 { + if !has_rights(fd_entry.rights, rights) { + return Err(__WASI_EACCES); + } + } + + let inode_idx = fd_entry.inode; + let inode = &inodes.arena[inode_idx]; + + let mut guard = inode.write(); + match guard.deref_mut() { + Kind::Socket { socket } => { + actor(socket)? + } + _ => { + return Err(__WASI_ENOTSOCK); + } + } + }; + + Ok(ret) +} + +fn __sock_upgrade( + thread: &WasiThread, + sock: __wasi_fd_t, + rights: __wasi_rights_t, + actor: F +) -> Result<(), __wasi_errno_t> +where F: FnOnce(&mut crate::state::InodeSocket) -> Result, __wasi_errno_t> +{ + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + + let fd_entry = state.fs.get_fd(sock)?; + if rights != 0 { + if !has_rights(fd_entry.rights, rights) { + return Err(__WASI_EACCES); + } + } + + let inode_idx = fd_entry.inode; + let inode = &inodes.arena[inode_idx]; + + let mut guard = inode.write(); + match guard.deref_mut() { + Kind::Socket { socket } => { + let new_socket = actor(socket)?; + + if let Some(mut new_socket) = new_socket { + std::mem::swap(socket, &mut new_socket); + } + } + _ => { + return Err(__WASI_ENOTSOCK); + } + } + + Ok(()) +} + #[must_use] -fn write_buffer_array( +fn write_buffer_array( memory: &Memory, from: &[Vec], - ptr_buffer: WasmPtr>, - buffer: WasmPtr, + ptr_buffer: WasmPtr, M>, + buffer: WasmPtr, ) -> __wasi_errno_t { - let ptrs = wasi_try_mem!(ptr_buffer.slice(memory, from.len() as u32)); + let ptrs = wasi_try_mem!(ptr_buffer.slice(memory, wasi_try!(to_offset::(from.len())))); - let mut current_buffer_offset = 0; + let mut current_buffer_offset = 0usize; for ((i, sub_buffer), ptr) in from.iter().enumerate().zip(ptrs.iter()) { trace!("ptr: {:?}, subbuffer: {:?}", ptr, sub_buffer); - let new_ptr = WasmPtr::new(buffer.offset() + current_buffer_offset); + let mut buf_offset = buffer.offset(); + buf_offset += wasi_try!(to_offset::(current_buffer_offset)); + let new_ptr = WasmPtr::new(buf_offset); wasi_try_mem!(ptr.write(new_ptr)); - let data = wasi_try_mem!(new_ptr.slice(memory, sub_buffer.len() as u32)); + let data = wasi_try_mem!(new_ptr.slice(memory, wasi_try!(to_offset::(sub_buffer.len())))); wasi_try_mem!(data.write_slice(sub_buffer)); - wasi_try_mem!(wasi_try_mem!(new_ptr.add_offset(sub_buffer.len() as u32)).write(memory, 0)); + wasi_try_mem!(wasi_try_mem!(new_ptr.add(wasi_try!(to_offset::(sub_buffer.len())))).write(memory, 0)); - current_buffer_offset += sub_buffer.len() as u32 + 1; + current_buffer_offset += sub_buffer.len() + 1; } __WASI_ESUCCESS @@ -154,10 +286,10 @@ fn get_current_time_in_nanos() -> Result<__wasi_timestamp_t, __wasi_errno_t> { /// - `char *argv_buf` /// A pointer to a buffer to write the argument string data. /// -pub fn args_get( +pub fn args_get( thread: &WasiThread, - argv: WasmPtr>, - argv_buf: WasmPtr, + argv: WasmPtr, M>, + argv_buf: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::args_get"); let (memory, state) = thread.get_memory_and_wasi_state(0); @@ -185,10 +317,10 @@ pub fn args_get( /// The number of arguments. /// - `size_t *argv_buf_size` /// The size of the argument string data. -pub fn args_sizes_get( +pub fn args_sizes_get( thread: &WasiThread, - argc: WasmPtr, - argv_buf_size: WasmPtr, + argc: WasmPtr, + argv_buf_size: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::args_sizes_get"); let (memory, state) = thread.get_memory_and_wasi_state(0); @@ -196,8 +328,9 @@ pub fn args_sizes_get( let argc = argc.deref(memory); let argv_buf_size = argv_buf_size.deref(memory); - let argc_val = state.args.len() as u32; - let argv_buf_size_val = state.args.iter().map(|v| v.len() as u32 + 1).sum(); + let argc_val: M::Offset = wasi_try!(state.args.len().try_into().map_err(|_| __WASI_EOVERFLOW)); + let argv_buf_size_val: usize = state.args.iter().map(|v| v.len() + 1).sum(); + let argv_buf_size_val: M::Offset = wasi_try!(argv_buf_size_val.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem!(argc.write(argc_val)); wasi_try_mem!(argv_buf_size.write(argv_buf_size_val)); @@ -214,10 +347,10 @@ pub fn args_sizes_get( /// Output: /// - `__wasi_timestamp_t *resolution` /// The resolution of the clock in nanoseconds -pub fn clock_res_get( +pub fn clock_res_get( thread: &WasiThread, clock_id: __wasi_clockid_t, - resolution: WasmPtr<__wasi_timestamp_t>, + resolution: WasmPtr<__wasi_timestamp_t, M>, ) -> __wasi_errno_t { trace!("wasi::clock_res_get"); let memory = thread.memory(); @@ -238,11 +371,11 @@ pub fn clock_res_get( /// Output: /// - `__wasi_timestamp_t *time` /// The value of the clock in nanoseconds -pub fn clock_time_get( +pub fn clock_time_get( thread: &WasiThread, clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, - time: WasmPtr<__wasi_timestamp_t>, + time: WasmPtr<__wasi_timestamp_t, M>, ) -> __wasi_errno_t { debug!( "wasi::clock_time_get clock_id: {}, precision: {}", @@ -251,7 +384,6 @@ pub fn clock_time_get( ); let memory = thread.memory(); - let out_addr = time.deref(memory); let t_out = wasi_try!(platform_clock_time_get(clock_id, precision)); wasi_try_mem!(time.write(memory, t_out as __wasi_timestamp_t)); @@ -272,10 +404,10 @@ pub fn clock_time_get( /// A pointer to a buffer to write the environment variable pointers. /// - `char *environ_buf` /// A pointer to a buffer to write the environment variable string data. -pub fn environ_get( +pub fn environ_get( thread: &WasiThread, - environ: WasmPtr>, - environ_buf: WasmPtr, + environ: WasmPtr, M>, + environ_buf: WasmPtr, ) -> __wasi_errno_t { debug!( "wasi::environ_get. Environ: {:?}, environ_buf: {:?}", @@ -294,10 +426,10 @@ pub fn environ_get( /// The number of environment variables. /// - `size_t *environ_buf_size` /// The size of the environment variable string data. -pub fn environ_sizes_get( +pub fn environ_sizes_get( thread: &WasiThread, - environ_count: WasmPtr, - environ_buf_size: WasmPtr, + environ_count: WasmPtr, + environ_buf_size: WasmPtr, ) -> __wasi_errno_t { trace!("wasi::environ_sizes_get"); let (memory, state) = thread.get_memory_and_wasi_state(0); @@ -305,8 +437,9 @@ pub fn environ_sizes_get( let environ_count = environ_count.deref(memory); let environ_buf_size = environ_buf_size.deref(memory); - let env_var_count = state.envs.len() as u32; - let env_buf_size = state.envs.iter().map(|v| v.len() as u32 + 1).sum(); + let env_var_count: M::Offset = wasi_try!(state.envs.len().try_into().map_err(|_| __WASI_EOVERFLOW)); + let env_buf_size: usize = state.envs.iter().map(|v| v.len() + 1).sum(); + let env_buf_size: M::Offset = wasi_try!(env_buf_size.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem!(environ_count.write(env_var_count)); wasi_try_mem!(environ_buf_size.write(env_buf_size)); @@ -360,7 +493,7 @@ pub fn fd_allocate( len: __wasi_filesize_t, ) -> __wasi_errno_t { debug!("wasi::fd_allocate"); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; @@ -378,10 +511,13 @@ pub fn fd_allocate( return __WASI_EBADF; } } + Kind::Socket { .. } => return __WASI_EBADF, + Kind::Pipe { .. } => return __WASI_EBADF, Kind::Buffer { buffer } => { buffer.resize(new_size as usize, 0); } Kind::Symlink { .. } => return __WASI_EBADF, + Kind::EventNotifications { .. } => return __WASI_EBADF, Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, } } @@ -403,7 +539,7 @@ pub fn fd_allocate( /// If `fd` is invalid or not open pub fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_close: fd={}", fd); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); @@ -419,7 +555,7 @@ pub fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { /// The file descriptor to sync pub fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_datasync"); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_DATASYNC) { return __WASI_EACCES; @@ -440,10 +576,10 @@ pub fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { /// Output: /// - `__wasi_fdstat_t *buf` /// The location where the metadata will be written -pub fn fd_fdstat_get( +pub fn fd_fdstat_get( thread: &WasiThread, fd: __wasi_fd_t, - buf_ptr: WasmPtr<__wasi_fdstat_t>, + buf_ptr: WasmPtr<__wasi_fdstat_t, M>, ) -> __wasi_errno_t { debug!( "wasi::fd_fdstat_get: fd={}, buf_ptr={}", @@ -452,9 +588,8 @@ pub fn fd_fdstat_get( ); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let stat = wasi_try!(state.fs.fdstat(inodes.deref(), fd)); - let buf = buf_ptr.deref(memory); - - wasi_try_mem!(buf.write(stat)); + + wasi_try_mem!(buf_ptr.write(memory, stat)); __WASI_ESUCCESS } @@ -472,7 +607,7 @@ pub fn fd_fdstat_set_flags( flags: __wasi_fdflags_t, ) -> __wasi_errno_t { debug!("wasi::fd_fdstat_set_flags"); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (_, state) = thread.get_memory_and_wasi_state(0); let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -500,7 +635,7 @@ pub fn fd_fdstat_set_rights( fs_rights_inheriting: __wasi_rights_t, ) -> __wasi_errno_t { debug!("wasi::fd_fdstat_set_rights"); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (_, state) = thread.get_memory_and_wasi_state(0); let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -525,10 +660,10 @@ pub fn fd_fdstat_set_rights( /// Output: /// - `__wasi_filestat_t *buf` /// Where the metadata from `fd` will be written -pub fn fd_filestat_get( +pub fn fd_filestat_get( thread: &WasiThread, fd: __wasi_fd_t, - buf: WasmPtr<__wasi_filestat_t>, + buf: WasmPtr<__wasi_filestat_t, M>, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_get"); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -539,8 +674,7 @@ pub fn fd_filestat_get( let stat = wasi_try!(state.fs.filestat_fd(inodes.deref(), fd)); - let buf = buf.deref(memory); - wasi_try_mem!(buf.write(stat)); + wasi_try_mem!(buf.write(memory, stat)); __WASI_ESUCCESS } @@ -558,7 +692,7 @@ pub fn fd_filestat_set_size( st_size: __wasi_filesize_t, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_set_size"); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; @@ -579,7 +713,10 @@ pub fn fd_filestat_set_size( Kind::Buffer { buffer } => { buffer.resize(st_size as usize, 0); } + Kind::Socket { .. } => return __WASI_EBADF, + Kind::Pipe { .. } => return __WASI_EBADF, Kind::Symlink { .. } => return __WASI_EBADF, + Kind::EventNotifications { .. } => return __WASI_EBADF, Kind::Dir { .. } | Kind::Root { .. } => return __WASI_EISDIR, } } @@ -605,7 +742,7 @@ pub fn fd_filestat_set_times( fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_set_times"); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_FILESTAT_SET_TIMES) { @@ -658,13 +795,13 @@ pub fn fd_filestat_set_times( /// Output: /// - `size_t nread` /// The number of bytes read -pub fn fd_pread( +pub fn fd_pread( thread: &WasiThread, fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t>, - iovs_len: u32, + iovs: WasmPtr<__wasi_iovec_t, M>, + iovs_len: M::Offset, offset: __wasi_filesize_t, - nread: WasmPtr, + nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_pread: fd={}, offset={}", fd, offset); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -715,6 +852,21 @@ pub fn fd_pread( return Ok(__WASI_EINVAL); } } + Kind::Socket { socket } => { + wasi_try_ok!( + socket.recv(memory, iovs), + thread + ) + } + Kind::Pipe { pipe } => { + wasi_try_ok!( + pipe.recv(memory, iovs), + thread + ) + } + Kind::EventNotifications { .. } => { + return Ok(__WASI_EINVAL) + } Kind::Dir { .. } | Kind::Root { .. } => return Ok(__WASI_EISDIR), Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"), Kind::Buffer { buffer } => { @@ -727,6 +879,7 @@ pub fn fd_pread( } }; + let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(nread_ref.write(bytes_read)); debug!("Success: {} bytes read", bytes_read); Ok(__WASI_ESUCCESS) @@ -740,26 +893,24 @@ pub fn fd_pread( /// Output: /// - `__wasi_prestat *buf` /// Where the metadata will be written -pub fn fd_prestat_get( +pub fn fd_prestat_get( thread: &WasiThread, fd: __wasi_fd_t, - buf: WasmPtr<__wasi_prestat_t>, + buf: WasmPtr<__wasi_prestat_t, M>, ) -> __wasi_errno_t { trace!("wasi::fd_prestat_get: fd={}", fd); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); - let prestat_ptr = buf.deref(memory); - - wasi_try_mem!(prestat_ptr.write(wasi_try!(state.fs.prestat_fd(inodes.deref(), fd)))); + wasi_try_mem!(buf.write(memory, wasi_try!(state.fs.prestat_fd(inodes.deref(), fd)))); __WASI_ESUCCESS } -pub fn fd_prestat_dir_name( +pub fn fd_prestat_dir_name( thread: &WasiThread, fd: __wasi_fd_t, - path: WasmPtr, - path_len: u32, + path: WasmPtr, + path_len: M::Offset, ) -> __wasi_errno_t { trace!( "wasi::fd_prestat_dir_name: fd={}, path_len={}", @@ -779,7 +930,8 @@ pub fn fd_prestat_dir_name( match guard.deref() { Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify this: null termination, etc - if inode_val.name.len() < path_len as usize { + let path_len: u64 = path_len.into(); + if (inode_val.name.len() as u64) < path_len { wasi_try_mem!(path_chars .subslice(0..inode_val.name.len() as u64) .write_slice(inode_val.name.as_bytes())); @@ -792,7 +944,7 @@ pub fn fd_prestat_dir_name( __WASI_EOVERFLOW } } - Kind::Symlink { .. } | Kind::Buffer { .. } | Kind::File { .. } => __WASI_ENOTDIR, + Kind::Symlink { .. } | Kind::Buffer { .. } | Kind::File { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => __WASI_ENOTDIR, } } @@ -810,13 +962,13 @@ pub fn fd_prestat_dir_name( /// Output: /// - `u32 *nwritten` /// Number of bytes written -pub fn fd_pwrite( +pub fn fd_pwrite( thread: &WasiThread, fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t>, - iovs_len: u32, + iovs: WasmPtr<__wasi_ciovec_t, M>, + iovs_len: M::Offset, offset: __wasi_filesize_t, - nwritten: WasmPtr, + nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_pwrite"); // TODO: refactor, this is just copied from `fd_write`... @@ -878,10 +1030,25 @@ pub fn fd_pwrite( return Ok(__WASI_EINVAL); } } + Kind::Socket { socket } => { + wasi_try_ok!( + socket.send(memory, iovs_arr), + thread + ) + } + Kind::Pipe { pipe } => { + wasi_try_ok!( + pipe.send(memory, iovs_arr), + thread + ) + } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify return Ok(__WASI_EISDIR); } + Kind::EventNotifications { .. } => { + return Ok(__WASI_EINVAL) + } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pwrite"), Kind::Buffer { buffer } => { wasi_try_ok!( @@ -893,6 +1060,7 @@ pub fn fd_pwrite( } }; + let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(nwritten_ref.write(bytes_written)); Ok(__WASI_ESUCCESS) @@ -910,12 +1078,13 @@ pub fn fd_pwrite( /// Output: /// - `u32 *nread` /// Number of bytes read -pub fn fd_read( +/// +pub fn fd_read( thread: &WasiThread, fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_iovec_t>, - iovs_len: u32, - nread: WasmPtr, + iovs: WasmPtr<__wasi_iovec_t, M>, + iovs_len: M::Offset, + nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_read: fd={}", fd); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -945,6 +1114,7 @@ pub fn fd_read( return Ok(__WASI_EACCES); } + let is_non_blocking = fd_entry.flags & __WASI_FDFLAG_NONBLOCK != 0; let offset = fd_entry.offset as usize; let inode_idx = fd_entry.inode; let inode = &inodes.arena[inode_idx]; @@ -965,10 +1135,62 @@ pub fn fd_read( return Ok(__WASI_EINVAL); } } + Kind::Socket { socket } => { + wasi_try_ok!( + socket.recv(memory, iovs_arr), + thread + ) + } + Kind::Pipe { pipe } => { + wasi_try_ok!( + pipe.recv(memory, iovs_arr), + thread + ) + } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify return Ok(__WASI_EISDIR); } + Kind::EventNotifications { counter, is_semaphore, wakers } => { + let counter = Arc::clone(counter); + let is_semaphore: bool = *is_semaphore; + let wakers = Arc::clone(wakers); + drop(guard); + drop(inodes); + + let (tx, rx) = mpsc::channel(); + { + let mut guard = wakers.lock().unwrap(); + guard.push_front(tx); + } + + let ret; + loop { + let val = counter.load(Ordering::Acquire); + if val > 0 { + let new_val = if is_semaphore { val - 1 } else { 0 }; + if counter.compare_exchange(val, new_val, Ordering::AcqRel, Ordering::Acquire).is_ok() { + let reader = val.to_ne_bytes(); + ret = wasi_try_ok!(read_bytes(&reader[..], memory, iovs_arr), thread); + break; + } else { + continue; + } + } + + // If its none blocking then exit + if is_non_blocking { + return Ok(__WASI_EAGAIN); + } + + // Yield for a fixed period of time and then check again + thread.yield_now()?; + if rx.recv_timeout(Duration::from_millis(5)).is_err() { + thread.sleep(Duration::from_millis(5))?; + } + } + ret + } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"), Kind::Buffer { buffer } => { wasi_try_ok!(read_bytes(&buffer[offset..], memory, iovs_arr), thread) @@ -980,11 +1202,12 @@ pub fn fd_read( let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); fd_entry.offset += bytes_read as u64; - + bytes_read } }; + let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(nread_ref.write(bytes_read)); Ok(__WASI_ESUCCESS) @@ -1005,13 +1228,13 @@ pub fn fd_read( /// - `u32 *bufused` /// The Number of bytes stored in `buf`; if less than `buf_len` then entire /// directory has been read -pub fn fd_readdir( +pub fn fd_readdir( thread: &WasiThread, fd: __wasi_fd_t, - buf: WasmPtr, - buf_len: u32, + buf: WasmPtr, + buf_len: M::Offset, cookie: __wasi_dircookie_t, - bufused: WasmPtr, + bufused: WasmPtr, ) -> __wasi_errno_t { trace!("wasi::fd_readdir"); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -1022,7 +1245,7 @@ pub fn fd_readdir( let bufused_ref = bufused.deref(memory); let working_dir = wasi_try!(state.fs.get_fd(fd)); let mut cur_cookie = cookie; - let mut buf_idx = 0; + let mut buf_idx = 0usize; let entries: Vec<(String, u8, u64)> = { let guard = inodes.arena[working_dir.inode].read(); @@ -1079,7 +1302,7 @@ pub fn fd_readdir( }) .collect() } - Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => { + Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { return __WASI_ENOTDIR } } @@ -1096,8 +1319,9 @@ pub fn fd_readdir( d_type: *wasi_file_type, }; let dirent_bytes = dirent_to_le_bytes(&dirent); + let buf_len: u64 = buf_len.into(); let upper_limit = std::cmp::min( - buf_len as usize - buf_idx, + (buf_len - buf_idx as u64) as usize, std::mem::size_of::<__wasi_dirent_t>(), ); for (i, b) in dirent_bytes.iter().enumerate().take(upper_limit) { @@ -1107,7 +1331,10 @@ pub fn fd_readdir( if upper_limit != std::mem::size_of::<__wasi_dirent_t>() { break; } - let upper_limit = std::cmp::min(buf_len as usize - buf_idx, namlen); + let upper_limit = std::cmp::min( + (buf_len - buf_idx as u64) as usize, + namlen + ); for (i, b) in entry_path_str.bytes().take(upper_limit).enumerate() { wasi_try_mem!(buf_arr.index((i + buf_idx) as u64).write(b)); } @@ -1117,7 +1344,8 @@ pub fn fd_readdir( } } - wasi_try_mem!(bufused_ref.write(buf_idx as u32)); + let buf_idx: M::Offset = wasi_try!(buf_idx.try_into().map_err(|_| __WASI_EOVERFLOW)); + wasi_try_mem!(bufused_ref.write(buf_idx)); __WASI_ESUCCESS } @@ -1130,7 +1358,7 @@ pub fn fd_readdir( /// Location to copy file descriptor to pub fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_renumber: from={}, to={}", from, to); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (_, state) = thread.get_memory_and_wasi_state(0); let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try!(fd_map.get_mut(&from).ok_or(__WASI_EBADF)); @@ -1146,6 +1374,68 @@ pub fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> _ __WASI_ESUCCESS } +/// ### `fd_dup()` +/// Duplicates the file handle +/// Inputs: +/// - `__wasi_fd_t fd` +/// File handle to be cloned +/// Outputs: +/// - `__wasi_fd_t fd` +/// The new file handle that is a duplicate of the original +pub fn fd_dup( + thread: &WasiThread, + fd: __wasi_fd_t, + ret_fd: WasmPtr<__wasi_fd_t, M>, +) -> __wasi_errno_t { + debug!("wasi::fd_dup"); + + let (memory, state) = thread.get_memory_and_wasi_state(0); + let fd = wasi_try!(state.fs.clone_fd(fd)); + + wasi_try_mem!( + ret_fd.write(memory, fd) + ); + + __WASI_ESUCCESS +} + +/// ### `fd_event()` +/// Creates a file handle for event notifications +pub fn fd_event( + thread: &WasiThread, + initial_val: u64, + flags: __wasi_eventfdflags, + ret_fd: WasmPtr<__wasi_fd_t, M>, +) -> __wasi_errno_t { + debug!("wasi::fd_event"); + + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + + let kind = Kind::EventNotifications { + counter: Arc::new(AtomicU64::new(initial_val)), + is_semaphore: flags & __WASI_EVENTFDFLAGS_SEMAPHORE != 0, + wakers: Default::default(), + }; + + let inode = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + kind, + false, + "event".to_string() + ); + let rights = __WASI_RIGHT_FD_READ | + __WASI_RIGHT_FD_WRITE | + __WASI_RIGHT_POLL_FD_READWRITE; + let fd = wasi_try!( + state.fs + .create_fd(rights, rights, 0, 0, inode) + ); + + wasi_try_mem!(ret_fd.write(memory, fd)); + + __WASI_ESUCCESS +} + /// ### `fd_seek()` /// Update file descriptor offset /// Inputs: @@ -1158,12 +1448,12 @@ pub fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> _ /// Output: /// - `__wasi_filesize_t *fd` /// The new offset relative to the start of the file -pub fn fd_seek( +pub fn fd_seek( thread: &WasiThread, fd: __wasi_fd_t, offset: __wasi_filedelta_t, whence: __wasi_whence_t, - newoffset: WasmPtr<__wasi_filesize_t>, + newoffset: WasmPtr<__wasi_filesize_t, M>, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_seek: fd={}, offset={}", fd, offset); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -1203,7 +1493,7 @@ pub fn fd_seek( Kind::Symlink { .. } => { unimplemented!("wasi::fd_seek not implemented for symlinks") } - Kind::Dir { .. } | Kind::Root { .. } => { + Kind::Dir { .. } | Kind::Root { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { // TODO: check this return Ok(__WASI_EINVAL); } @@ -1240,7 +1530,7 @@ pub fn fd_seek( pub fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_sync"); debug!("=> fd={}", fd); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_SYNC) { return __WASI_EACCES; @@ -1259,7 +1549,7 @@ pub fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { } } Kind::Root { .. } | Kind::Dir { .. } => return __WASI_EISDIR, - Kind::Buffer { .. } | Kind::Symlink { .. } => return __WASI_EINVAL, + Kind::Buffer { .. } | Kind::Symlink { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => return __WASI_EINVAL, } } @@ -1274,10 +1564,10 @@ pub fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { /// Output: /// - `__wasi_filesize_t *offset` /// The offset of `fd` relative to the start of the file -pub fn fd_tell( +pub fn fd_tell( thread: &WasiThread, fd: __wasi_fd_t, - offset: WasmPtr<__wasi_filesize_t>, + offset: WasmPtr<__wasi_filesize_t, M>, ) -> __wasi_errno_t { debug!("wasi::fd_tell"); let (memory, state) = thread.get_memory_and_wasi_state(0); @@ -1308,12 +1598,12 @@ pub fn fd_tell( /// Number of bytes written /// Errors: /// -pub fn fd_write( +pub fn fd_write( thread: &WasiThread, fd: __wasi_fd_t, - iovs: WasmPtr<__wasi_ciovec_t>, - iovs_len: u32, - nwritten: WasmPtr, + iovs: WasmPtr<__wasi_ciovec_t, M>, + iovs_len: M::Offset, + nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_write: fd={}", fd); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -1374,10 +1664,42 @@ pub fn fd_write( return Ok(__WASI_EINVAL); } } + Kind::Socket { socket } => { + wasi_try_ok!( + socket.send(memory, iovs_arr), + thread + ) + } + Kind::Pipe { pipe } => { + wasi_try_ok!( + pipe.send(memory, iovs_arr), + thread + ) + } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify return Ok(__WASI_EISDIR); } + Kind::EventNotifications { counter, wakers, .. } => { + let mut val = 0u64.to_ne_bytes(); + let written = wasi_try_ok!(write_bytes(&mut val[..], memory, iovs_arr)); + if written != val.len() { + return Ok(__WASI_EINVAL); + } + let val = u64::from_ne_bytes(val); + + counter.fetch_add(val, Ordering::AcqRel); + { + let mut guard = wakers.lock().unwrap(); + while let Some(wake) = guard.pop_back() { + if wake.send(()).is_ok() { + break; + } + } + } + + written + } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"), Kind::Buffer { buffer } => { wasi_try_ok!(write_bytes(&mut buffer[offset..], memory, iovs_arr), thread) @@ -1397,11 +1719,59 @@ pub fn fd_write( } }; + let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(nwritten_ref.write(bytes_written)); Ok(__WASI_ESUCCESS) } +/// ### `fd_pipe()` +/// Creates ta pipe that feeds data between two file handles +/// Output: +/// - `__wasi_fd_t` +/// First file handle that represents one end of the pipe +/// - `__wasi_fd_t` +/// Second file handle that represents the other end of the pipe +pub fn fd_pipe( + thread: &WasiThread, + ro_fd1: WasmPtr<__wasi_fd_t, M>, + ro_fd2: WasmPtr<__wasi_fd_t, M>, +) -> __wasi_errno_t { + trace!("wasi::fd_pipe"); + + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + + let (pipe1, pipe2) = WasiPipe::new(); + + let inode1 = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::Pipe { pipe: pipe1 }, + false, + "pipe".to_string() + ); + let inode2 = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + Kind::Pipe { pipe: pipe2 }, + false, + "pipe".to_string() + ); + + let rights = super::state::all_socket_rights(); + let fd1 = wasi_try!( + state.fs + .create_fd(rights, rights, 0, 0, inode1) + ); + let fd2 = wasi_try!( + state.fs + .create_fd(rights, rights, 0, 0, inode2) + ); + + wasi_try_mem!(ro_fd1.write(memory, fd1)); + wasi_try_mem!(ro_fd2.write(memory, fd2)); + + __WASI_ESUCCESS +} + /// ### `path_create_directory()` /// Create directory at a path /// Inputs: @@ -1415,11 +1785,11 @@ pub fn fd_write( /// Required Rights: /// - __WASI_RIGHT_PATH_CREATE_DIRECTORY /// This right must be set on the directory that the file is created in (TODO: verify that this is true) -pub fn path_create_directory( +pub fn path_create_directory( thread: &WasiThread, fd: __wasi_fd_t, - path: WasmPtr, - path_len: u32, + path: WasmPtr, + path_len: M::Offset, ) -> __wasi_errno_t { debug!("wasi::path_create_directory"); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); @@ -1542,13 +1912,13 @@ pub fn path_create_directory( /// Output: /// - `__wasi_file_stat_t *buf` /// The location where the metadata will be stored -pub fn path_filestat_get( +pub fn path_filestat_get( thread: &WasiThread, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: u32, - buf: WasmPtr<__wasi_filestat_t>, + path: WasmPtr, + path_len: M::Offset, + buf: WasmPtr<__wasi_filestat_t, M>, ) -> __wasi_errno_t { debug!("wasi::path_filestat_get"); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); @@ -1634,12 +2004,12 @@ pub fn path_filestat_get_internal( /// The timestamp that the last modified time attribute is set to /// - `__wasi_fstflags_t fst_flags` /// A bitmask controlling which attributes are set -pub fn path_filestat_set_times( +pub fn path_filestat_set_times( thread: &WasiThread, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: u32, + path: WasmPtr, + path_len: M::Offset, st_atim: __wasi_timestamp_t, st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, @@ -1711,15 +2081,15 @@ pub fn path_filestat_set_times( /// String containing the new file path /// - `u32 old_path_len` /// Length of the `new_path` string -pub fn path_link( +pub fn path_link( thread: &WasiThread, old_fd: __wasi_fd_t, old_flags: __wasi_lookupflags_t, - old_path: WasmPtr, - old_path_len: u32, + old_path: WasmPtr, + old_path_len: M::Offset, new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: u32, + new_path: WasmPtr, + new_path_len: M::Offset, ) -> __wasi_errno_t { debug!("wasi::path_link"); if old_flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 { @@ -1769,7 +2139,7 @@ pub fn path_link( entries.insert(new_entry_name, source_inode); } Kind::Root { .. } => return __WASI_EINVAL, - Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => { + Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { return __WASI_ENOTDIR } } @@ -1803,17 +2173,17 @@ pub fn path_link( /// The new file descriptor /// Possible Errors: /// - `__WASI_EACCES`, `__WASI_EBADF`, `__WASI_EFAULT`, `__WASI_EFBIG?`, `__WASI_EINVAL`, `__WASI_EIO`, `__WASI_ELOOP`, `__WASI_EMFILE`, `__WASI_ENAMETOOLONG?`, `__WASI_ENFILE`, `__WASI_ENOENT`, `__WASI_ENOTDIR`, `__WASI_EROFS`, and `__WASI_ENOTCAPABLE` -pub fn path_open( +pub fn path_open( thread: &WasiThread, dirfd: __wasi_fd_t, dirflags: __wasi_lookupflags_t, - path: WasmPtr, - path_len: u32, + path: WasmPtr, + path_len: M::Offset, o_flags: __wasi_oflags_t, fs_rights_base: __wasi_rights_t, fs_rights_inheriting: __wasi_rights_t, fs_flags: __wasi_fdflags_t, - fd: WasmPtr<__wasi_fd_t>, + fd: WasmPtr<__wasi_fd_t, M>, ) -> __wasi_errno_t { debug!("wasi::path_open"); if dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 { @@ -1821,7 +2191,8 @@ pub fn path_open( } let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); /* TODO: find actual upper bound on name size (also this is a path, not a name :think-fish:) */ - if path_len > 1024 * 1024 { + let path_len64: u64 = path_len.into(); + if path_len64 > 1024u64 * 1024u64 { return __WASI_ENAMETOOLONG; } @@ -1914,7 +2285,7 @@ pub fn path_open( .map_err(fs_error_into_wasi_err))); } Kind::Buffer { .. } => unimplemented!("wasi::path_open for Buffer type files"), - Kind::Dir { .. } | Kind::Root { .. } => {} + Kind::Dir { .. } | Kind::Root { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => {} Kind::Symlink { base_po_dir, path_to_symlink, @@ -2040,14 +2411,14 @@ pub fn path_open( /// Pointer to characters containing the path that the symlink points to /// - `u32 buf_used` /// The number of bytes written to `buf` -pub fn path_readlink( +pub fn path_readlink( thread: &WasiThread, dir_fd: __wasi_fd_t, - path: WasmPtr, - path_len: u32, - buf: WasmPtr, - buf_len: u32, - buf_used: WasmPtr, + path: WasmPtr, + path_len: M::Offset, + buf: WasmPtr, + buf_len: M::Offset, + buf_used: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::path_readlink"); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); @@ -2066,17 +2437,19 @@ pub fn path_readlink( if let Kind::Symlink { relative_path, .. } = guard.deref() { let rel_path_str = relative_path.to_string_lossy(); debug!("Result => {:?}", rel_path_str); + let buf_len: u64 = buf_len.into(); let bytes = rel_path_str.bytes(); - if bytes.len() >= buf_len as usize { + if bytes.len() as u64 >= buf_len { return __WASI_EOVERFLOW; } let bytes: Vec<_> = bytes.collect(); - let out = wasi_try_mem!(buf.slice(memory, bytes.len() as u32)); + let out = wasi_try_mem!(buf.slice(memory, wasi_try!(to_offset::(bytes.len())))); wasi_try_mem!(out.write_slice(&bytes[..])); // should we null terminate this? - wasi_try_mem!(buf_used.deref(memory).write(bytes.len() as u32)); + let bytes_len: M::Offset = wasi_try!(bytes.len().try_into().map_err(|_| __WASI_EOVERFLOW)); + wasi_try_mem!(buf_used.deref(memory).write(bytes_len)); } else { return __WASI_EINVAL; } @@ -2086,11 +2459,11 @@ pub fn path_readlink( } /// Returns __WASI_ENOTEMTPY if directory is not empty -pub fn path_remove_directory( +pub fn path_remove_directory( thread: &WasiThread, fd: __wasi_fd_t, - path: WasmPtr, - path_len: u32, + path: WasmPtr, + path_len: M::Offset, ) -> __wasi_errno_t { // TODO check if fd is a dir, ensure it's within sandbox, etc. debug!("wasi::path_remove_directory"); @@ -2170,14 +2543,14 @@ pub fn path_remove_directory( /// Pointer to UTF8 bytes, the new file name /// - `u32 new_path_len` /// The number of bytes to read from `new_path` -pub fn path_rename( +pub fn path_rename( thread: &WasiThread, old_fd: __wasi_fd_t, - old_path: WasmPtr, - old_path_len: u32, + old_path: WasmPtr, + old_path_len: M::Offset, new_fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: u32, + new_path: WasmPtr, + new_path_len: M::Offset, ) -> __wasi_errno_t { debug!( "wasi::path_rename: old_fd = {}, new_fd = {}", @@ -2222,6 +2595,7 @@ pub fn path_rename( out_path } Kind::Root { .. } => return __WASI_ENOTCAPABLE, + Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => return __WASI_EINVAL, Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => { unreachable!("Fatal internal logic error: parent of inode is not a directory") } @@ -2235,6 +2609,7 @@ pub fn path_rename( wasi_try!(entries.remove(&source_entry_name).ok_or(__WASI_ENOENT)) } Kind::Root { .. } => return __WASI_ENOTCAPABLE, + Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => return __WASI_EINVAL, Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => { unreachable!("Fatal internal logic error: parent of inode is not a directory") } @@ -2293,6 +2668,9 @@ pub fn path_rename( } Kind::Buffer { .. } => {} Kind::Symlink { .. } => {} + Kind::Socket { .. } => {} + Kind::Pipe { .. } => {} + Kind::EventNotifications { .. } => {} Kind::Root { .. } => unreachable!("The root can not be moved"), } } @@ -2324,13 +2702,13 @@ pub fn path_rename( /// Array of UTF-8 bytes representing the target path /// - `u32 new_path_len` /// The number of bytes to read from `new_path` -pub fn path_symlink( +pub fn path_symlink( thread: &WasiThread, - old_path: WasmPtr, - old_path_len: u32, + old_path: WasmPtr, + old_path_len: M::Offset, fd: __wasi_fd_t, - new_path: WasmPtr, - new_path_len: u32, + new_path: WasmPtr, + new_path_len: M::Offset, ) -> __wasi_errno_t { debug!("wasi::path_symlink"); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); @@ -2368,6 +2746,7 @@ pub fn path_symlink( } } Kind::Root { .. } => return __WASI_ENOTCAPABLE, + Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => return __WASI_EINVAL, Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => { unreachable!("get_parent_inode_at_path returned something other than a Dir or Root") } @@ -2420,11 +2799,11 @@ pub fn path_symlink( /// Array of UTF-8 bytes representing the path /// - `u32 path_len` /// The number of bytes in the `path` array -pub fn path_unlink_file( +pub fn path_unlink_file( thread: &WasiThread, fd: __wasi_fd_t, - path: WasmPtr, - path_len: u32, + path: WasmPtr, + path_len: M::Offset, ) -> __wasi_errno_t { debug!("wasi::path_unlink_file"); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); @@ -2530,12 +2909,12 @@ pub fn path_unlink_file( /// Output: /// - `u32 nevents` /// The number of events seen -pub fn poll_oneoff( +pub fn poll_oneoff( thread: &WasiThread, - in_: WasmPtr<__wasi_subscription_t>, - out_: WasmPtr<__wasi_event_t>, - nsubscriptions: u32, - nevents: WasmPtr, + in_: WasmPtr<__wasi_subscription_t, M>, + out_: WasmPtr<__wasi_event_t, M>, + nsubscriptions: M::Offset, + nevents: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::poll_oneoff"); trace!(" => nsubscriptions = {}", nsubscriptions); @@ -2543,7 +2922,7 @@ pub fn poll_oneoff( let subscription_array = wasi_try_mem_ok!(in_.slice(memory, nsubscriptions)); let event_array = wasi_try_mem_ok!(out_.slice(memory, nsubscriptions)); - let mut events_seen = 0; + let mut events_seen: u32 = 0; let out_ptr = nevents.deref(memory); let mut fd_guards = vec![]; @@ -2640,6 +3019,11 @@ pub fn poll_oneoff( return Ok(__WASI_EBADF); } } + Kind::Socket { .. } + | Kind::Pipe { .. } + | Kind::EventNotifications { .. } => { + return Ok(__WASI_EBADF); + } Kind::Dir { .. } | Kind::Root { .. } | Kind::Buffer { .. } @@ -2764,20 +3148,42 @@ pub fn poll_oneoff( events_seen += 1; } } - wasi_try_mem_ok!(out_ptr.write(events_seen as u32)); + let events_seen: M::Offset = wasi_try_ok!(events_seen.try_into().map_err(|_| __WASI_EOVERFLOW)); + wasi_try_mem_ok!(out_ptr.write(events_seen)); Ok(__WASI_ESUCCESS) } +/// ### `proc_exit()` +/// Terminate the process normally. An exit code of 0 indicates successful +/// termination of the program. The meanings of other values is dependent on +/// the environment. +/// Inputs: +/// - `__wasi_exitcode_t` +/// Exit code to return to the operating system pub fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { debug!("wasi::proc_exit, {}", code); Err(WasiError::Exit(code)) } +/// ### `proc_raise()` +/// Send a signal to the process of the calling thread. +/// Note: This is similar to `raise` in POSIX. +/// Inputs: +/// - `__wasi_signal_t` +/// Signal to be raised for this process pub fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { debug!("wasi::proc_raise"); unimplemented!("wasi::proc_raise") } +/// ### `sched_yield()` +/// Yields execution of the thread +pub fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { + trace!("wasi::sched_yield"); + thread.yield_now()?; + Ok(__WASI_ESUCCESS) +} + /// ### `random_get()` /// Fill buffer with high-quality random data. This function may be slow and block /// Inputs: @@ -2785,14 +3191,19 @@ pub fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { /// A pointer to a buffer where the random bytes will be written /// - `size_t buf_len` /// The number of bytes that will be written -pub fn random_get(thread: &WasiThread, buf: u32, buf_len: u32) -> __wasi_errno_t { +pub fn random_get( + thread: &WasiThread, + buf: WasmPtr, + buf_len: M::Offset +) -> __wasi_errno_t { trace!("wasi::random_get buf_len: {}", buf_len); let memory = thread.memory(); - let mut u8_buffer = vec![0; buf_len as usize]; + let buf_len64: u64 = buf_len.into(); + let mut u8_buffer = vec![0; buf_len64 as usize]; let res = getrandom::getrandom(&mut u8_buffer); match res { Ok(()) => { - let buf = wasi_try_mem!(WasmPtr::::new(buf).slice(memory, buf_len)); + let buf = wasi_try_mem!(buf.slice(memory, buf_len)); wasi_try_mem!(buf.write_slice(&u8_buffer)); __WASI_ESUCCESS } @@ -2800,42 +3211,2084 @@ pub fn random_get(thread: &WasiThread, buf: u32, buf_len: u32) -> __wasi_errno_t } } -/// ### `sched_yield()` -/// Yields execution of the thread -pub fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { - trace!("wasi::sched_yield"); - thread.yield_now()?; - Ok(__WASI_ESUCCESS) +/// ### `tty_get()` +/// Retrieves the current state of the TTY +pub fn tty_get( + thread: &WasiThread, + tty_state: WasmPtr<__wasi_tty_t, M>, +) -> __wasi_errno_t { + debug!("wasi::tty_stdin"); + + let state = thread.env.runtime.tty_get(); + let state = __wasi_tty_t { + cols: state.cols, + rows: state.rows, + width: state.width, + height: state.height, + stdin_tty: match state.stdin_tty { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }, + stdout_tty: match state.stdout_tty { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }, + stderr_tty: match state.stderr_tty { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }, + echo: match state.echo { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }, + line_buffered: match state.line_buffered { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE, + }, + }; + + let memory = thread.memory(); + wasi_try_mem!(tty_state.write(memory, state)); + + __WASI_ESUCCESS } -pub fn sock_recv( +/// ### `tty_set()` +/// Updates the properties of the rect +pub fn tty_set( thread: &WasiThread, - sock: __wasi_fd_t, - ri_data: WasmPtr<__wasi_iovec_t>, - ri_data_len: u32, - ri_flags: __wasi_riflags_t, - ro_datalen: WasmPtr, - ro_flags: WasmPtr<__wasi_roflags_t>, + tty_state: WasmPtr<__wasi_tty_t, M>, ) -> __wasi_errno_t { - trace!("wasi::sock_recv"); - unimplemented!("wasi::sock_recv") + debug!("wasi::tty_stdout"); + + let memory = thread.memory(); + let state = wasi_try_mem!(tty_state.read(memory)); + let state = super::runtime::WasiTtyState { + cols: state.cols, + rows: state.rows, + width: state.width, + height: state.height, + stdin_tty: match state.stdin_tty { + __WASI_BOOL_FALSE => false, + __WASI_BOOL_TRUE => true, + _ => return __WASI_EINVAL + }, + stdout_tty: match state.stdout_tty { + __WASI_BOOL_FALSE => false, + __WASI_BOOL_TRUE => true, + _ => return __WASI_EINVAL + }, + stderr_tty: match state.stderr_tty { + __WASI_BOOL_FALSE => false, + __WASI_BOOL_TRUE => true, + _ => return __WASI_EINVAL + }, + echo: match state.echo { + __WASI_BOOL_FALSE => false, + __WASI_BOOL_TRUE => true, + _ => return __WASI_EINVAL + }, + line_buffered: match state.line_buffered { + __WASI_BOOL_FALSE => false, + __WASI_BOOL_TRUE => true, + _ => return __WASI_EINVAL + }, + }; + + thread.env.runtime.tty_set(state); + + __WASI_ESUCCESS } -pub fn sock_send( + +/// ### `getcwd()` +/// Returns the current working directory +/// If the path exceeds the size of the buffer then this function +/// will fill the path_len with the needed size and return EOVERFLOW +pub fn getcwd( thread: &WasiThread, - sock: __wasi_fd_t, - si_data: WasmPtr<__wasi_ciovec_t>, - si_data_len: u32, - si_flags: __wasi_siflags_t, - so_datalen: WasmPtr, + path: WasmPtr, + path_len: WasmPtr, ) -> __wasi_errno_t { - trace!("wasi::sock_send"); - unimplemented!("wasi::sock_send") + debug!("wasi::getpwd"); + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + + let (_, cur_dir) = wasi_try!(state.fs.get_current_dir( + inodes.deref_mut() + )); + let cur_dir = cur_dir.as_bytes(); + + let max_path_len = wasi_try_mem!(path_len.read(memory)); + let path_slice = wasi_try_mem!(path.slice(memory, max_path_len)); + + wasi_try_mem!(path_len.write(memory, wasi_try!(to_offset::(cur_dir.len())))); + let max_path_len: u64 = max_path_len.into(); + if cur_dir.len() as u64 > max_path_len { + return __WASI_EOVERFLOW; + } + + wasi_try_mem!(path_slice.write_slice(cur_dir)); + __WASI_ESUCCESS } -pub fn sock_shutdown( + +/// ### `chdir()` +/// Sets the current working directory +pub fn chdir( thread: &WasiThread, - sock: __wasi_fd_t, - how: __wasi_sdflags_t, + path: WasmPtr, + path_len: M::Offset, +) -> __wasi_errno_t { + debug!("wasi::chdir"); + + let (memory, state) = thread.get_memory_and_wasi_state(0); + let path = unsafe { get_input_str!(memory, path, path_len) }; + + state.fs.set_current_dir(path.as_str()); + __WASI_ESUCCESS +} + +/// ### `thread_spawn()` +/// Creates a new thread by spawning that shares the same +/// memory address space, file handles and main event loops. +/// The function referenced by the fork call must be +/// exported by the web assembly process. +/// +/// ## Parameters +/// +/// * `name` - Name of the function that will be invoked as a new thread +/// * `user_data` - User data that will be supplied to the function when its called +/// * `reactor` - Indicates if the function will operate as a reactor or +/// as a normal thread. Reactors will be repeatable called +/// whenever IO work is available to be processed. +/// +/// ## Return +/// +/// Returns the thread index of the newly created thread +/// (indices always start from zero) +pub fn thread_spawn( + thread: &WasiThread, + method: WasmPtr, + method_len: M::Offset, + user_data: u64, + reactor: __wasi_bool_t, + ret_tid: WasmPtr<__wasi_tid_t, M>, +) -> __wasi_errno_t { + debug!("wasi::thread_spawn"); + let memory = thread.memory(); + let method = unsafe { get_input_str!(memory, method, method_len) }; + let reactor = match reactor { + __WASI_BOOL_FALSE => false, + __WASI_BOOL_TRUE => true, + _ => return __WASI_EINVAL + }; + let child = wasi_try!( + thread.env.runtime + .thread_spawn(method.as_str(), user_data, reactor) + .map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + }) + ); + let child: __wasi_tid_t = child.into(); + + wasi_try_mem!( + ret_tid.write(memory, child) + ); + __WASI_ESUCCESS +} + +/// ### `thread_sleep()` +/// Sends the current thread to sleep for a period of time +/// +/// ## Parameters +/// +/// * `duration` - Amount of time that the thread should sleep +pub fn thread_sleep( + thread: &WasiThread, + duration: __wasi_timestamp_t, +) -> Result<__wasi_errno_t, WasiError> { + debug!("wasi::thread_sleep"); + + let duration = Duration::from_nanos(duration as u64); + thread.sleep(duration)?; + Ok(__WASI_ESUCCESS) +} + +/// ### `thread_id()` +/// Returns the index of the current thread +/// (threads indices are sequencial from zero) +pub fn thread_id( + thread: &WasiThread, + ret_tid: WasmPtr<__wasi_tid_t, M>, ) -> __wasi_errno_t { - trace!("wasi::sock_shutdown"); - unimplemented!("wasi::sock_shutdown") + debug!("wasi::thread_id"); + + let tid: __wasi_tid_t = thread.id.into(); + wasi_try_mem!( + ret_tid.write(thread.memory(), tid) + ); + __WASI_ESUCCESS +} + +/// ### `thread_join()` +/// Joins this thread with another thread, blocking this +/// one until the other finishes +/// +/// ## Parameters +/// +/// * `tid` - Handle of the thread to wait on +pub fn thread_join( + thread: &WasiThread, + tid: __wasi_tid_t, +) -> __wasi_errno_t { + debug!("wasi::thread_join"); + + let tid: WasiThreadId = tid.into(); + wasi_try!( + thread.env.runtime() + .thread_join(tid) + .map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + }) + ); + + __WASI_ESUCCESS +} + +/// ### `thread_parallelism()` +/// Returns the available parallelism which is normally the +/// number of available cores that can run concurrently +pub fn thread_parallelism( + thread: &WasiThread, + ret_parallelism: WasmPtr, +) -> __wasi_errno_t { + debug!("wasi::thread_parallelism"); + + let parallelism = wasi_try!( + thread.runtime() + .thread_parallelism() + .map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + }) + ); + let parallelism: M::Offset = wasi_try!(parallelism.try_into().map_err(|_| __WASI_EOVERFLOW)); + wasi_try_mem!( + ret_parallelism.write(thread.memory(), parallelism) + ); + __WASI_ESUCCESS +} + +/// ### `getpid()` +/// Returns the handle of the current process +pub fn getpid( + thread: &WasiThread, + ret_pid: WasmPtr<__wasi_pid_t, M>, +) -> __wasi_errno_t { + debug!("wasi::getpid"); + + let pid = thread.runtime().getpid(); + if let Some(pid) = pid { + wasi_try_mem!( + ret_pid.write(thread.memory(), pid as __wasi_pid_t) + ); + __WASI_ESUCCESS + } else { + __WASI_ENOTSUP + } +} + +/// ### `thread_exit()` +/// Terminates the current running thread, if this is the last thread then +/// the process will also exit with the specified exit code. An exit code +/// of 0 indicates successful termination of the thread. The meanings of +/// other values is dependent on the environment. +/// +/// ## Parameters +/// +/// * `rval` - The exit code returned by the process. +pub fn thread_exit( + thread: &WasiThread, + exitcode: __wasi_exitcode_t, +) -> Result<__wasi_errno_t, WasiError> { + debug!("wasi::thread_exit"); + Err(WasiError::Exit(exitcode)) +} + +/// ### `bus_spawn_local()` +/// Spawns a new bus process for a particular web WebAssembly +/// binary that is referenced by its process name. +/// +/// ## Parameters +/// +/// * `name` - Name of the process to be spawned +/// * `chroot` - Indicates if the process will chroot or not +/// * `args` - List of the arguments to pass the process +/// (entries are separated by line feeds) +/// * `preopen` - List of the preopens for this process +/// (entries are separated by line feeds) +/// * `stdin` - How will stdin be handled +/// * `stdout` - How will stdout be handled +/// * `stderr` - How will stderr be handled +/// * `working_dir` - Working directory where this process should run +/// (passing '.' will use the current directory) +/// +/// ## Return +/// +/// Returns a bus process id that can be used to invoke calls +pub fn bus_spawn_local( + thread: &WasiThread, + name: WasmPtr, + name_len: M::Offset, + chroot: __wasi_bool_t, + args: WasmPtr, + args_len: M::Offset, + preopen: WasmPtr, + preopen_len: M::Offset, + stdin: __wasi_stdiomode_t, + stdout: __wasi_stdiomode_t, + stderr: __wasi_stdiomode_t, + working_dir: WasmPtr, + working_dir_len: M::Offset, + ret_handles: WasmPtr<__wasi_bus_handles_t, M>, +) -> __wasi_errno_t { + debug!("wasi::bus_spawn_local"); + unimplemented!("wasi::bus_spawn_local") +} + +/// ### `bus_spawn_remote()` +/// Spawns a new bus process for a particular web WebAssembly +/// binary that is referenced by its process name on a remote instance +/// +/// ## Parameters +/// +/// * `name` - Name of the process to be spawned +/// * `chroot` - Indicates if the process will chroot or not +/// * `args` - List of the arguments to pass the process +/// (entries are separated by line feeds) +/// * `preopen` - List of the preopens for this process +/// (entries are separated by line feeds) +/// * `working_dir` - Working directory where this process should run +/// (passing '.' will use the current directory) +/// * `stdin` - How will stdin be handled +/// * `stdout` - How will stdout be handled +/// * `stderr` - How will stderr be handled +/// * `instance` - Instance identifier where this process will be spawned +/// * `token` - Acceess token used to authenticate with the instance +/// +/// ## Return +/// +/// Returns a bus process id that can be used to invoke calls +pub fn bus_spawn_remote( + thread: &WasiThread, + name: WasmPtr, + name_len: M::Offset, + chroot: __wasi_bool_t, + args: WasmPtr, + args_len: M::Offset, + preopen: WasmPtr, + preopen_len: M::Offset, + working_dir: WasmPtr, + working_dir_len: M::Offset, + stdin: __wasi_stdiomode_t, + stdout: __wasi_stdiomode_t, + stderr: __wasi_stdiomode_t, + instance: WasmPtr, + instance_len: M::Offset, + token: WasmPtr, + token_len: M::Offset, + ret_handles: WasmPtr<__wasi_bus_handles_t, M>, +) -> __wasi_errno_t { + debug!("wasi::bus_spawn_remote"); + unimplemented!("wasi::bus_spawn_remote") +} + +/// ### `bus_close()` +/// Closes a bus process and releases all associated resources +/// +/// ## Parameters +/// +/// * `bid` - Handle of the bus process handle to be closed +pub fn bus_close( + thread: &WasiThread, + bid: __wasi_bid_t, +) -> __wasi_errno_t { + debug!("wasi::bus_close"); + unimplemented!("wasi::bus_close") +} + +/// ### `bus_invoke()` +/// Invokes a call within a running bus process. +/// +/// ## Parameters +/// +/// * `bid` - Handle of the bus process to invoke the call within +/// * `parent` - Optional parent bus call that this is related to +/// * `keep_alive` - Causes the call handle to remain open even when A +/// reply is received. It is then the callers responsibility +/// to invoke 'bus_drop' when they are finished with the call +/// * `topic` - Topic that describes the type of call to made +/// * `format` - Format of the data pushed onto the bus +/// * `buf` - The buffer where data to be transmitted is stored +pub fn bus_invoke( + thread: &WasiThread, + bid: __wasi_bid_t, + cid: WasmPtr<__wasi_option_cid_t, M>, + keep_alive: __wasi_bool_t, + topic: WasmPtr, + topic_len: M::Offset, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: M::Offset, + ret_cid: WasmPtr<__wasi_cid_t, M>, +) -> __wasi_errno_t { + debug!("wasi::bus_invoke"); + unimplemented!("wasi::bus_invoke") +} + +/// ### `bus_fault()` +/// Causes a fault on a particular call that was made +/// to this process from another process; where 'bid' +/// is the callering process context. +/// +/// ## Parameters +/// +/// * `cid` - Handle of the call to raise a fault on +/// * `fault` - Fault to be raised on the bus +pub fn bus_fault( + thread: &WasiThread, + cid: __wasi_cid_t, + fault: __bus_errno_t, +) -> __wasi_errno_t { + debug!("wasi::bus_fault"); + unimplemented!("wasi::bus_fault") +} + +/// ### `bus_drop()` +/// Closes a bus call based on its bus call handle +/// +/// ## Parameters +/// +/// * `cid` - Handle of the bus call handle to be dropped +pub fn bus_drop( + thread: &WasiThread, + cid: __wasi_cid_t, +) -> __wasi_errno_t { + debug!("wasi::bus_drop"); + unimplemented!("wasi::bus_drop") +} + +/// ### `bus_reply()` +/// Replies to a call that was made to this process +/// from another process; where 'cid' is the call context. +/// This will may also drop the handle and release any +/// associated resources (if keepalive is not set) +/// +/// ## Parameters +/// +/// * `cid` - Handle of the call to send a reply on +/// * `format` - Format of the data pushed onto the bus +/// * `buf` - The buffer where data to be transmitted is stored +pub fn bus_reply( + thread: &WasiThread, + cid: __wasi_cid_t, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: M::Offset, +) -> __wasi_errno_t { + debug!("wasi::bus_reply"); + unimplemented!("wasi::bus_reply") +} + +/// ### `bus_callback()` +/// Invokes a callback within the calling process against +/// a particular bus call represented by 'cid'. +/// +/// ## Parameters +/// +/// * `cid` - Handle of the call where a callback will be send +/// * `topic` - Topic that describes the type of callback +/// * `format` - Format of the data pushed onto the bus +/// * `buf` - The buffer where data to be transmitted is stored +pub fn bus_callback( + thread: &WasiThread, + cid: __wasi_cid_t, + topic: WasmPtr, + topic_len: M::Offset, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: M::Offset, +) -> __wasi_errno_t { + debug!("wasi::bus_callback"); + unimplemented!("wasi::bus_callback") +} + +/// ### `bus_listen()` +/// Tells the operating system that this process is +/// now listening for bus calls on a particular topic +/// +/// ## Parameters +/// +/// * `parent` - Optional parent bus call that this is related to +/// * `topic` - Topic that describes the process will listen forcalls on +pub fn bus_listen( + thread: &WasiThread, + parent: WasmPtr<__wasi_option_cid_t, M>, + topic: WasmPtr, + topic_len: M::Offset, +) -> __wasi_errno_t { + debug!("wasi::bus_listen"); + unimplemented!("wasi::bus_listen") +} + +/// ### `bus_poll()` +/// Polls for any outstanding events from a particular +/// bus process by its handle +/// +/// ## Parameters +/// +/// * `bid` - Handle of the bus process to poll for new events +/// (if no process is supplied then it polls for the current process) +/// * `timeout` - Timeout before the poll returns, if one passed 0 +/// as the timeout then this call is non blocking. +/// * `events` - An events buffer that will hold any received bus events +/// +/// ## Return +/// +/// Returns the number of events that have occured +pub fn bus_poll( + thread: &WasiThread, + bid: WasmPtr<__wasi_option_bid_t, M>, + timeout: WasmPtr<__wasi_timestamp_t, M>, + events: WasmPtr, + nevents: M::Offset, + ret_nevents: WasmPtr, +) -> __wasi_errno_t { + debug!("wasi::bus_poll"); + unimplemented!("wasi::bus_poll") +} + +/// ### `bus_poll_data()` +/// Receives the next event data from the bus +/// +/// ## Parameters +/// +/// * `bid` - Handle of the bus process to poll for new events +/// (if no process is supplied then it polls for the current process) +/// * `timeout` - Timeout before the poll returns, if one passed 0 +/// as the timeout then this call is non blocking. +/// * `topic` - The topic that describes the event that happened +/// * `buf` - The buffer where event data is stored +/// +/// ## Return +/// +/// Returns the number of events that have occured +pub fn bus_poll_data( + thread: &WasiThread, + bid: WasmPtr<__wasi_option_bid_t, M>, + timeout: WasmPtr<__wasi_timestamp_t, M>, + topic: WasmPtr, + topic_len: M::Offset, + buf: WasmPtr, + buf_len: M::Offset, + ret_evt: WasmPtr<__wasi_busevent_data_t, M>, +) -> __wasi_errno_t { + debug!("wasi::bus_poll_data"); + unimplemented!("wasi::bus_poll_data") +} + +/// ### `ws_connect()` +/// Connects to a websocket at a particular network URL +/// +/// ## Parameters +/// +/// * `url` - URL of the web socket destination to connect to +/// +/// ## Return +/// +/// Returns a socket handle which is used to send and receive data +pub fn ws_connect( + thread: &WasiThread, + url: WasmPtr, + url_len: M::Offset, + ret_sock: WasmPtr<__wasi_fd_t, M>, +) -> __wasi_errno_t { + debug!("wasi::ws_connect"); + let memory = thread.memory(); + let url = unsafe { get_input_str!(memory, url, url_len) }; + + let socket = wasi_try!( + thread.net().ws_connect(url.as_str()).map_err(net_error_into_wasi_err) + ); + + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + + let kind = Kind::Socket { + socket: InodeSocket::new(InodeSocketKind::WebSocket(socket)) + }; + + let inode = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + kind, + false, + "socket".to_string() + ); + let rights = super::state::all_socket_rights(); + let fd = wasi_try!( + state.fs + .create_fd(rights, rights, 0, 0, inode) + ); + + wasi_try_mem!(ret_sock.write(memory, fd)); + + __WASI_ESUCCESS +} + +/// ### `http_request()` +/// Makes a HTTP request to a remote web resource and +/// returns a socket handles that are used to send and receive data +/// +/// ## Parameters +/// +/// * `url` - URL of the HTTP resource to connect to +/// * `method` - HTTP method to be invoked +/// * `headers` - HTTP headers to attach to the request +/// (headers seperated by lines) +/// * `gzip` - Should the request body be compressed +/// +/// ## Return +/// +/// The body of the response can be streamed from the returned +/// file handle +pub fn http_request( + thread: &WasiThread, + url: WasmPtr, + url_len: M::Offset, + method: WasmPtr, + method_len: M::Offset, + headers: WasmPtr, + headers_len: M::Offset, + gzip: __wasi_bool_t, + ret_handles: WasmPtr<__wasi_http_handles_t, M>, +) -> __wasi_errno_t { + debug!("wasi::http_request"); + let memory = thread.memory(); + let url = unsafe { get_input_str!(memory, url, url_len) }; + let method = unsafe { get_input_str!(memory, method, method_len) }; + let headers = unsafe { get_input_str!(memory, headers, headers_len) }; + + let gzip = match gzip { + __WASI_BOOL_FALSE => false, + __WASI_BOOL_TRUE => true, + _ => return __WASI_EINVAL + }; + + let socket = wasi_try!( + thread.net() + .http_request(url.as_str(), method.as_str(), headers.as_str(), gzip) + .map_err(net_error_into_wasi_err) + ); + let socket_req = SocketHttpRequest { + request: socket.request, + response: None, + headers: None, + status: socket.status.clone() + }; + let socket_res = SocketHttpRequest { + request: None, + response: socket.response, + headers: None, + status: socket.status.clone() + }; + let socket_hdr = SocketHttpRequest { + request: None, + response: None, + headers: socket.headers, + status: socket.status.clone() + }; + + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + + let kind_req = Kind::Socket { + socket: InodeSocket::new(InodeSocketKind::HttpRequest(Mutex::new(socket_req), InodeHttpSocketType::Request)) + }; + let kind_res = Kind::Socket { + socket: InodeSocket::new(InodeSocketKind::HttpRequest(Mutex::new(socket_res), InodeHttpSocketType::Response)) + }; + let kind_hdr = Kind::Socket { + socket: InodeSocket::new(InodeSocketKind::HttpRequest(Mutex::new(socket_hdr), InodeHttpSocketType::Headers)) + }; + + let inode_req = state.fs.create_inode_with_default_stat(inodes.deref_mut(), kind_req, false, "http_request".to_string()); + let inode_res = state.fs.create_inode_with_default_stat(inodes.deref_mut(), kind_res, false, "http_response".to_string()); + let inode_hdr = state.fs.create_inode_with_default_stat(inodes.deref_mut(), kind_hdr, false, "http_headers".to_string()); + let rights = super::state::all_socket_rights(); + + let handles = __wasi_http_handles_t { + req: wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode_req)), + res: wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode_res)), + hdr: wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode_hdr)), + }; + + wasi_try_mem!(ret_handles.write(memory, handles)); + + __WASI_ESUCCESS +} + +/// ### `http_status()` +/// Retrieves the status of a HTTP request +/// +/// ## Parameters +/// +/// * `fd` - Handle of the HTTP request +/// * `status` - Pointer to a buffer that will be filled with the current +/// status of this HTTP request +pub fn http_status( + thread: &WasiThread, + sock: __wasi_fd_t, + status: WasmPtr<__wasi_http_status_t, M>, +) -> __wasi_errno_t { + debug!("wasi::http_status"); + + let memory = thread.memory(); + let ref_status = status.deref(memory); + + let http_status = wasi_try!( + __sock_actor(thread, sock, 0, |socket| { + socket.http_status() + }) + ); + + // Write everything else and return the status to the caller + let status = __wasi_http_status_t { + ok: __WASI_BOOL_TRUE, + redirect: match http_status.redirected { + true => __WASI_BOOL_TRUE, + false => __WASI_BOOL_FALSE + }, + size: wasi_try!(http_status.size.try_into().map_err(|_| __WASI_EOVERFLOW)), + status: http_status.status + }; + + wasi_try_mem!(ref_status.write(status)); + + __WASI_ESUCCESS +} + +/// ### `port_bridge()` +/// Securely connects to a particular remote network +/// +/// ## Parameters +/// +/// * `network` - Fully qualified identifier for the network +/// * `token` - Access token used to authenticate with the network +/// * `security` - Level of encryption to encapsulate the network connection with +pub fn port_bridge( + thread: &WasiThread, + network: WasmPtr, + network_len: M::Offset, + token: WasmPtr, + token_len: M::Offset, + security: __wasi_streamsecurity_t, +) -> __wasi_errno_t { + debug!("wasi::port_bridge"); + let memory = thread.memory(); + let network = unsafe { get_input_str!(memory, network, network_len) }; + let token = unsafe { get_input_str!(memory, token, token_len) }; + let security = match security { + __WASI_STREAM_SECURITY_UNENCRYPTED => StreamSecurity::Unencrypted, + __WASI_STREAM_SECURITY_ANY_ENCRYPTION => StreamSecurity::AnyEncyption, + __WASI_STREAM_SECURITY_CLASSIC_ENCRYPTION => StreamSecurity::ClassicEncryption, + __WASI_STREAM_SECURITY_DOUBLE_ENCRYPTION => StreamSecurity::DoubleEncryption, + _ => return __WASI_EINVAL + }; + + wasi_try!( + thread.net().bridge(network.as_str(), token.as_str(), security).map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_unbridge()` +/// Disconnects from a remote network +pub fn port_unbridge( + thread: &WasiThread, +) -> __wasi_errno_t { + debug!("wasi::port_unbridge"); + wasi_try!( + thread.net().unbridge().map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_dhcp_acquire()` +/// Acquires a set of IP addresses using DHCP +pub fn port_dhcp_acquire( + thread: &WasiThread, +) -> __wasi_errno_t { + debug!("wasi::port_dhcp_acquire"); + wasi_try!( + thread.net().dhcp_acquire().map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_addr_add()` +/// Adds another static address to the local port +/// +/// ## Parameters +/// +/// * `addr` - Address to be added +pub fn port_addr_add( + thread: &WasiThread, + ip: WasmPtr<__wasi_cidr_t, M>, +) -> __wasi_errno_t { + debug!("wasi::port_addr_add"); + let memory = thread.memory(); + let cidr = wasi_try!(super::state::read_cidr(memory, ip)); + wasi_try!( + thread.net().ip_add(cidr.ip, cidr.prefix).map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_addr_remove()` +/// Removes an address from the local port +/// +/// ## Parameters +/// +/// * `addr` - Address to be removed +pub fn port_addr_remove( + thread: &WasiThread, + ip: WasmPtr<__wasi_addr_t, M>, +) -> __wasi_errno_t { + debug!("wasi::port_addr_remove"); + let memory = thread.memory(); + let ip = wasi_try!(super::state::read_ip(memory, ip)); + wasi_try!( + thread.net().ip_remove(ip).map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_addr_clear()` +/// Clears all the addresses on the local port +pub fn port_addr_clear( + thread: &WasiThread, +) -> __wasi_errno_t { + debug!("wasi::port_addr_clear"); + wasi_try!( + thread.net().ip_clear().map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_mac()` +/// Returns the MAC address of the local port +pub fn port_mac( + thread: &WasiThread, + ret_mac: WasmPtr<__wasi_hardwareaddress_t, M>, +) -> __wasi_errno_t { + debug!("wasi::port_mac"); + let memory = thread.memory(); + let mac = wasi_try!( + thread.net().mac().map_err(net_error_into_wasi_err) + ); + let mac = __wasi_hardwareaddress_t { + octs: mac + }; + wasi_try_mem!( + ret_mac.write(memory, mac) + ); + __WASI_ESUCCESS +} + +/// ### `port_ip_list()` +/// Returns a list of all the addresses owned by the local port +/// This function fills the output buffer as much as possible. +/// If the buffer is not big enough then the naddrs address will be +/// filled with the buffer size needed and the EOVERFLOW will be returned +/// +/// ## Parameters +/// +/// * `addrs` - The buffer where addresses will be stored +/// +/// ## Return +/// +/// The number of addresses returned. +pub fn port_addr_list( + thread: &WasiThread, + addrs: WasmPtr<__wasi_cidr_t, M>, + naddrs: WasmPtr, +) -> __wasi_errno_t { + debug!("wasi::port_addr_list"); + let memory = thread.memory(); + let max_addrs = wasi_try_mem!(naddrs.read(memory)); + let max_addrs: u64 = wasi_try!(max_addrs.try_into().map_err(|_| __WASI_EOVERFLOW)); + let ref_addrs = wasi_try_mem!(addrs.slice(memory, wasi_try!(to_offset::(max_addrs as usize)))); + + let addrs = wasi_try!( + thread.net() + .ip_list() + .map_err(net_error_into_wasi_err) + ); + + let addrs_len: M::Offset = wasi_try!(addrs.len().try_into().map_err(|_| __WASI_EOVERFLOW)); + wasi_try_mem!(naddrs.write(memory, addrs_len)); + if addrs.len() as u64 > max_addrs { + return __WASI_EOVERFLOW; + } + + for n in 0..addrs.len() { + let nip = ref_addrs.index(n as u64); + super::state::write_cidr(memory, nip.as_ptr::(), addrs.get(n).unwrap().clone()); + } + + __WASI_ESUCCESS +} + +/// ### `port_gateway_set()` +/// Adds a default gateway to the port +/// +/// ## Parameters +/// +/// * `addr` - Address of the default gateway +pub fn port_gateway_set( + thread: &WasiThread, + ip: WasmPtr<__wasi_addr_t, M>, +) -> __wasi_errno_t { + debug!("wasi::port_gateway_set"); + let memory = thread.memory(); + let ip = wasi_try!(super::state::read_ip(memory, ip)); + + wasi_try!( + thread.net().gateway_set(ip).map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_route_add()` +/// Adds a new route to the local port +pub fn port_route_add( + thread: &WasiThread, + cidr: WasmPtr<__wasi_cidr_t, M>, + via_router: WasmPtr<__wasi_addr_t, M>, + preferred_until: WasmPtr<__wasi_option_timestamp_t, M>, + expires_at: WasmPtr<__wasi_option_timestamp_t, M>, +) -> __wasi_errno_t { + debug!("wasi::port_route_add"); + let memory = thread.memory(); + let cidr = wasi_try!(super::state::read_cidr(memory, cidr)); + let via_router = wasi_try!(super::state::read_ip(memory, via_router)); + let preferred_until = wasi_try_mem!(preferred_until.read(memory)); + let preferred_until = match preferred_until.tag { + __WASI_OPTION_NONE => None, + __WASI_OPTION_SOME => { + Some(Duration::from_nanos(preferred_until.u)) + }, + _ => return __WASI_EINVAL + }; + let expires_at = wasi_try_mem!(expires_at.read(memory)); + let expires_at = match expires_at.tag { + __WASI_OPTION_NONE => None, + __WASI_OPTION_SOME => { + Some(Duration::from_nanos(expires_at.u)) + }, + _ => return __WASI_EINVAL + }; + + wasi_try!( + thread.net().route_add(cidr, via_router, preferred_until, expires_at).map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_route_remove()` +/// Removes an existing route from the local port +pub fn port_route_remove( + thread: &WasiThread, + ip: WasmPtr<__wasi_addr_t, M>, +) -> __wasi_errno_t { + debug!("wasi::port_route_remove"); + let memory = thread.memory(); + let ip = wasi_try!(super::state::read_ip(memory, ip)); + wasi_try!( + thread.net().route_remove(ip).map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_route_clear()` +/// Clears all the routes in the local port +pub fn port_route_clear( + thread: &WasiThread, +) -> __wasi_errno_t { + debug!("wasi::port_route_clear"); + wasi_try!( + thread.net().route_clear().map_err(net_error_into_wasi_err) + ); + __WASI_ESUCCESS +} + +/// ### `port_route_list()` +/// Returns a list of all the routes owned by the local port +/// This function fills the output buffer as much as possible. +/// If the buffer is too small this will return EOVERFLOW and +/// fill nroutes with the size of the buffer needed. +/// +/// ## Parameters +/// +/// * `routes` - The buffer where routes will be stored +pub fn port_route_list( + thread: &WasiThread, + routes: WasmPtr<__wasi_route_t, M>, + nroutes: WasmPtr, +) -> __wasi_errno_t { + debug!("wasi::port_route_list"); + let memory = thread.memory(); + let nroutes = nroutes.deref(memory); + let max_routes: usize = wasi_try!(wasi_try_mem!(nroutes.read()).try_into().map_err(|_| __WASI_EINVAL)); + let ref_routes = wasi_try_mem!(routes.slice(memory, wasi_try!(to_offset::(max_routes)))); + + let routes = wasi_try!( + thread.net().route_list().map_err(net_error_into_wasi_err) + ); + + let routes_len: M::Offset = wasi_try!(routes.len().try_into().map_err(|_| __WASI_EINVAL)); + wasi_try_mem!(nroutes.write(routes_len)); + if routes.len() > max_routes { + return __WASI_EOVERFLOW; + } + + for n in 0..routes.len() { + let nroute = ref_routes.index(n as u64); + super::state::write_route(memory, nroute.as_ptr::(), routes.get(n).unwrap().clone()); + } + + __WASI_ESUCCESS +} + +/// ### `sock_shutdown()` +/// Shut down socket send and receive channels. +/// Note: This is similar to `shutdown` in POSIX. +/// +/// ## Parameters +/// +/// * `how` - Which channels on the socket to shut down. +pub fn sock_shutdown( + thread: &WasiThread, + sock: __wasi_fd_t, + how: __wasi_sdflags_t, +) -> __wasi_errno_t { + debug!("wasi::sock_shutdown"); + + let both = __WASI_SHUT_RD | __WASI_SHUT_WR; + let how = match how { + __WASI_SHUT_RD => std::net::Shutdown::Read, + __WASI_SHUT_WR => std::net::Shutdown::Write, + a if a == both => std::net::Shutdown::Both, + _ => return __WASI_EINVAL + }; + + wasi_try!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_SHUTDOWN, |socket| { + socket.shutdown(how) + })); + + __WASI_ESUCCESS +} + +/// ### `sock_status()` +/// Returns the current status of a socket +pub fn sock_status( + thread: &WasiThread, + sock: __wasi_fd_t, + ret_status: WasmPtr<__wasi_sockstatus_t, M> +) -> __wasi_errno_t { + debug!("wasi::sock_status"); + + let status = wasi_try!( + __sock_actor(thread, sock, 0, |socket| { + socket.status() + }) + ); + + use super::state::WasiSocketStatus; + let status = match status { + WasiSocketStatus::Opening => __WASI_SOCK_STATUS_OPENING, + WasiSocketStatus::Opened => __WASI_SOCK_STATUS_OPENED, + WasiSocketStatus::Closed => __WASI_SOCK_STATUS_CLOSED, + WasiSocketStatus::Failed => __WASI_SOCK_STATUS_FAILED, + }; + + wasi_try_mem!(ret_status.write(thread.memory(), status)); + + __WASI_ESUCCESS +} + +/// ### `sock_addr_local()` +/// Returns the local address to which the socket is bound. +/// +/// Note: This is similar to `getsockname` in POSIX +/// +/// When successful, the contents of the output buffer consist of an IP address, +/// either IP4 or IP6. +/// +/// ## Parameters +/// +/// * `fd` - Socket that the address is bound to +pub fn sock_addr_local( + thread: &WasiThread, + sock: __wasi_fd_t, + ret_addr: WasmPtr<__wasi_addr_port_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_addr_local"); + + let addr = wasi_try!( + __sock_actor(thread, sock, 0, |socket| { + socket.addr_local() + }) + ); + wasi_try!( + super::state::write_ip_port(thread.memory(), ret_addr, addr.ip(), addr.port()) + ); + __WASI_ESUCCESS +} + +/// ### `sock_addr_peer()` +/// Returns the remote address to which the socket is connected to. +/// +/// Note: This is similar to `getpeername` in POSIX +/// +/// When successful, the contents of the output buffer consist of an IP address, +/// either IP4 or IP6. +/// +/// ## Parameters +/// +/// * `fd` - Socket that the address is bound to +pub fn sock_addr_peer( + thread: &WasiThread, + sock: __wasi_fd_t, + ro_addr: WasmPtr<__wasi_addr_port_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_addr_peer"); + + let addr = wasi_try!( + __sock_actor(thread, sock, 0, |socket| { + socket.addr_peer() + }) + ); + wasi_try!( + super::state::write_ip_port(thread.memory(), ro_addr, addr.ip(), addr.port()) + ); + __WASI_ESUCCESS +} + +/// ### `sock_open()` +/// Create an endpoint for communication. +/// +/// creates an endpoint for communication and returns a file descriptor +/// tor that refers to that endpoint. The file descriptor returned by a successful +/// call will be the lowest-numbered file descriptor not currently open +/// for the process. +/// +/// Note: This is similar to `socket` in POSIX using PF_INET +/// +/// ## Parameters +/// +/// * `af` - Address family +/// * `socktype` - Socket type, either datagram or stream +/// * `sock_proto` - Socket protocol +/// +/// ## Return +/// +/// The file descriptor of the socket that has been opened. +pub fn sock_open( + thread: &WasiThread, + af: __wasi_addressfamily_t, + ty: __wasi_socktype_t, + pt: __wasi_sockproto_t, + ro_sock: WasmPtr<__wasi_fd_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_open"); + + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + + let kind = match ty { + __WASI_SOCK_TYPE_STREAM | + __WASI_SOCK_TYPE_DGRAM => { + Kind::Socket { + socket: InodeSocket::new(InodeSocketKind::PreSocket { + family: af, + ty, + pt, + addr: None, + only_v6: false, + reuse_port: false, + reuse_addr: false, + send_buf_size: None, + recv_buf_size: None, + send_timeout: None, + recv_timeout: None, + connect_timeout: None, + accept_timeout: None, + }) + } + }, + _ => return __WASI_ENOTSUP, + }; + + let inode = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + kind, + false, + "socket".to_string() + ); + let rights = super::state::all_socket_rights(); + let fd = wasi_try!( + state.fs + .create_fd(rights, rights, 0, 0, inode) + ); + + wasi_try_mem!(ro_sock.write(memory, fd)); + + __WASI_ESUCCESS +} + +/// ### `sock_set_opt_flag()` +/// Sets a particular socket setting +/// Note: This is similar to `setsockopt` in POSIX for SO_REUSEADDR +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `sockopt` - Socket option to be set +/// * `flag` - Value to set the option to +pub fn sock_set_opt_flag( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + flag: __wasi_bool_t, +) -> __wasi_errno_t { + debug!("wasi::sock_set_opt_flag(ty={})", opt); + + let flag = match flag { + __WASI_BOOL_FALSE => false, + __WASI_BOOL_TRUE => true, + _ => return __WASI_EINVAL, + }; + + let option: super::state::WasiSocketOption = opt.into(); + wasi_try!( + __sock_actor_mut(thread, sock, 0, |socket| { + socket.set_opt_flag(option, flag) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_get_opt_flag()` +/// Retrieve status of particular socket seting +/// Note: This is similar to `getsockopt` in POSIX for SO_REUSEADDR +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `sockopt` - Socket option to be retrieved +pub fn sock_get_opt_flag( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_flag: WasmPtr<__wasi_bool_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_get_opt_flag(ty={})", opt); + let memory = thread.memory(); + + let option: super::state::WasiSocketOption = opt.into(); + let flag = wasi_try!( + __sock_actor(thread, sock, 0, |socket| { + socket.get_opt_flag(option) + }) + ); + let flag = match flag { + false => __WASI_BOOL_FALSE, + true => __WASI_BOOL_TRUE + }; + + wasi_try_mem!(ret_flag.write(memory, flag)); + + __WASI_ESUCCESS +} + +/// ### `sock_set_opt_time()` +/// Sets one of the times the socket +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `sockopt` - Socket option to be set +/// * `time` - Value to set the time to +pub fn sock_set_opt_time( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + time: WasmPtr<__wasi_option_timestamp_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_set_opt_time(ty={})", opt); + + let memory = thread.memory(); + let time = wasi_try_mem!(time.read(memory)); + let time = match time.tag { + __WASI_OPTION_NONE => None, + __WASI_OPTION_SOME => { + Some(Duration::from_nanos(time.u)) + }, + _ => return __WASI_EINVAL + }; + + let ty = match opt { + __WASI_SOCK_OPTION_RECV_TIMEOUT => wasmer_vnet::TimeType::ReadTimeout, + __WASI_SOCK_OPTION_SEND_TIMEOUT => wasmer_vnet::TimeType::WriteTimeout, + __WASI_SOCK_OPTION_CONNECT_TIMEOUT => wasmer_vnet::TimeType::ConnectTimeout, + __WASI_SOCK_OPTION_ACCEPT_TIMEOUT => wasmer_vnet::TimeType::AcceptTimeout, + __WASI_SOCK_OPTION_LINGER => wasmer_vnet::TimeType::Linger, + _ => return __WASI_EINVAL + }; + + let option: super::state::WasiSocketOption = opt.into(); + wasi_try!( + __sock_actor_mut(thread, sock, 0, |socket| { + socket.set_opt_time(ty, time) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_get_opt_time()` +/// Retrieve one of the times on the socket +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `sockopt` - Socket option to be retrieved +pub fn sock_get_opt_time( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_time: WasmPtr<__wasi_option_timestamp_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_get_opt_time(ty={})", opt); + let memory = thread.memory(); + + let ty = match opt { + __WASI_SOCK_OPTION_RECV_TIMEOUT => wasmer_vnet::TimeType::ReadTimeout, + __WASI_SOCK_OPTION_SEND_TIMEOUT => wasmer_vnet::TimeType::WriteTimeout, + __WASI_SOCK_OPTION_CONNECT_TIMEOUT => wasmer_vnet::TimeType::ConnectTimeout, + __WASI_SOCK_OPTION_ACCEPT_TIMEOUT => wasmer_vnet::TimeType::AcceptTimeout, + __WASI_SOCK_OPTION_LINGER => wasmer_vnet::TimeType::Linger, + _ => return __WASI_EINVAL + }; + + let time = wasi_try!( + __sock_actor(thread, sock, 0, |socket| { + socket.opt_time(ty) + }) + ); + let time = match time { + None => __wasi_option_timestamp_t { + tag: __WASI_OPTION_NONE, + u: 0 + }, + Some(timeout) => __wasi_option_timestamp_t { + tag: __WASI_OPTION_SOME, + u: timeout.as_nanos() as __wasi_timestamp_t + }, + }; + + wasi_try_mem!(ret_time.write(memory, time)); + + __WASI_ESUCCESS +} + +/// ### `sock_set_opt_size() +/// Set size of particular option for this socket +/// Note: This is similar to `setsockopt` in POSIX for SO_RCVBUF +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `opt` - Socket option to be set +/// * `size` - Buffer size +pub fn sock_set_opt_size( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + size: __wasi_filesize_t, +) -> __wasi_errno_t { + debug!("wasi::sock_set_opt_size(ty={})", opt); + + let ty = match opt { + __WASI_SOCK_OPTION_RECV_TIMEOUT => wasmer_vnet::TimeType::ReadTimeout, + __WASI_SOCK_OPTION_SEND_TIMEOUT => wasmer_vnet::TimeType::WriteTimeout, + __WASI_SOCK_OPTION_CONNECT_TIMEOUT => wasmer_vnet::TimeType::ConnectTimeout, + __WASI_SOCK_OPTION_ACCEPT_TIMEOUT => wasmer_vnet::TimeType::AcceptTimeout, + __WASI_SOCK_OPTION_LINGER => wasmer_vnet::TimeType::Linger, + _ => return __WASI_EINVAL + }; + + let option: super::state::WasiSocketOption = opt.into(); + wasi_try!( + __sock_actor_mut(thread, sock, 0, |socket| { + match opt { + __WASI_SOCK_OPTION_RECV_BUF_SIZE => { + socket.set_recv_buf_size(size as usize) + }, + __WASI_SOCK_OPTION_SEND_BUF_SIZE => { + socket.set_send_buf_size(size as usize) + }, + __WASI_SOCK_OPTION_TTL => { + socket.set_ttl(size as u32) + }, + __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => { + socket.set_multicast_ttl_v4(size as u32) + }, + _ => Err(__WASI_EINVAL) + } + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_get_opt_size()` +/// Retrieve the size of particular option for this socket +/// Note: This is similar to `getsockopt` in POSIX for SO_RCVBUF +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `sockopt` - Socket option to be retrieved +pub fn sock_get_opt_size( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_size: WasmPtr<__wasi_filesize_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_get_opt_size(ty={})", opt); + let memory = thread.memory(); + + let size = wasi_try!( + __sock_actor(thread, sock, 0, |socket| { + match opt { + __WASI_SOCK_OPTION_RECV_BUF_SIZE => { + socket.recv_buf_size().map(|a| a as __wasi_filesize_t) + }, + __WASI_SOCK_OPTION_SEND_BUF_SIZE => { + socket.send_buf_size().map(|a| a as __wasi_filesize_t) + }, + __WASI_SOCK_OPTION_TTL => { + socket.ttl().map(|a| a as __wasi_filesize_t) + }, + __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => { + socket.multicast_ttl_v4().map(|a| a as __wasi_filesize_t) + }, + _ => Err(__WASI_EINVAL) + } + }) + ); + wasi_try_mem!(ret_size.write(memory, size)); + + __WASI_ESUCCESS +} + +/// ### `sock_join_multicast_v4()` +/// Joins a particular multicast IPv4 group +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `multiaddr` - Multicast group to joined +/// * `interface` - Interface that will join +pub fn sock_join_multicast_v4( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip4_t, M>, + iface: WasmPtr<__wasi_addr_ip4_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_join_multicast_v4"); + + let memory = thread.memory(); + let multiaddr = wasi_try!(super::state::read_ip_v4(memory, multiaddr)); + let iface = wasi_try!(super::state::read_ip_v4(memory, iface)); + wasi_try!( + __sock_actor_mut(thread, sock, 0, |socket| { + socket.join_multicast_v4(multiaddr, iface) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_leave_multicast_v4()` +/// Leaves a particular multicast IPv4 group +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `multiaddr` - Multicast group to leave +/// * `interface` - Interface that will left +pub fn sock_leave_multicast_v4( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip4_t, M>, + iface: WasmPtr<__wasi_addr_ip4_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_leave_multicast_v4"); + + let memory = thread.memory(); + let multiaddr = wasi_try!(super::state::read_ip_v4(memory, multiaddr)); + let iface = wasi_try!(super::state::read_ip_v4(memory, iface)); + wasi_try!( + __sock_actor_mut(thread, sock, 0, |socket| { + socket.leave_multicast_v4(multiaddr, iface) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_join_multicast_v6()` +/// Joins a particular multicast IPv6 group +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `multiaddr` - Multicast group to joined +/// * `interface` - Interface that will join +pub fn sock_join_multicast_v6( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip6_t, M>, + iface: u32, +) -> __wasi_errno_t { + debug!("wasi::sock_join_multicast_v6"); + + let memory = thread.memory(); + let multiaddr = wasi_try!(super::state::read_ip_v6(memory, multiaddr)); + wasi_try!( + __sock_actor_mut(thread, sock, 0, |socket| { + socket.join_multicast_v6(multiaddr, iface) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_leave_multicast_v6()` +/// Leaves a particular multicast IPv6 group +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `multiaddr` - Multicast group to leave +/// * `interface` - Interface that will left +pub fn sock_leave_multicast_v6( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip6_t, M>, + iface: u32, +) -> __wasi_errno_t { + debug!("wasi::sock_leave_multicast_v6"); + + let memory = thread.memory(); + let multiaddr = wasi_try!(super::state::read_ip_v6(memory, multiaddr)); + wasi_try!( + __sock_actor_mut(thread, sock, 0, |socket| { + socket.leave_multicast_v6(multiaddr, iface) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_bind()` +/// Bind a socket +/// Note: This is similar to `bind` in POSIX using PF_INET +/// +/// ## Parameters +/// +/// * `fd` - File descriptor of the socket to be bind +/// * `addr` - Address to bind the socket to +pub fn sock_bind( + thread: &WasiThread, + sock: __wasi_fd_t, + addr: WasmPtr<__wasi_addr_port_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_bind"); + + let addr = wasi_try!(super::state::read_ip_port(thread.memory(), addr)); + let addr = SocketAddr::new(addr.0, addr.1); + wasi_try!( + __sock_upgrade(thread, sock, __WASI_RIGHT_SOCK_BIND, |socket| { + socket.bind(thread.net(), addr) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_listen()` +/// Listen for connections on a socket +/// +/// Polling the socket handle will wait until a connection +/// attempt is made +/// +/// Note: This is similar to `listen` +/// +/// ## Parameters +/// +/// * `fd` - File descriptor of the socket to be bind +/// * `backlog` - Maximum size of the queue for pending connections +pub fn sock_listen( + thread: &WasiThread, + sock: __wasi_fd_t, + backlog: M::Offset, +) -> __wasi_errno_t { + debug!("wasi::sock_listen"); + + let backlog: usize = wasi_try!(backlog.try_into().map_err(|_| __WASI_EINVAL)); + wasi_try!( + __sock_upgrade(thread, sock, __WASI_RIGHT_SOCK_BIND, |socket| { + socket.listen(thread.net(), backlog) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_accept()` +/// Accept a new incoming connection. +/// Note: This is similar to `accept` in POSIX. +/// +/// ## Parameters +/// +/// * `fd` - The listening socket. +/// * `flags` - The desired values of the file descriptor flags. +/// +/// ## Return +/// +/// New socket connection +pub fn sock_accept( + thread: &WasiThread, + sock: __wasi_fd_t, + fd_flags: __wasi_fdflags_t, + ro_fd: WasmPtr<__wasi_fd_t, M>, + ro_addr: WasmPtr<__wasi_addr_port_t, M>, +) -> Result<__wasi_errno_t, WasiError> { + debug!("wasi::sock_accept"); + + let (child, addr) = { + let mut ret; + let (_, state) = thread.get_memory_and_wasi_state(0); + loop { + wasi_try_ok!( + match __sock_actor + ( + thread, + sock, + __WASI_RIGHT_SOCK_ACCEPT, + |socket| socket.accept_timeout(fd_flags, Duration::from_millis(5)) + ) { + Ok(a) => { + ret = a; + break; + }, + Err(__WASI_ETIMEDOUT) => { + thread.yield_now()?; + continue; + }, + Err(__WASI_EAGAIN) => { + thread.sleep(Duration::from_millis(5))?; + continue; + } + Err(err) => Err(err) + } + ); + } + ret + }; + + let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + + let kind = Kind::Socket { + socket: InodeSocket::new(InodeSocketKind::TcpStream(child)) + }; + let inode = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + kind, + false, + "socket".to_string() + ); + + let rights = super::state::all_socket_rights(); + let fd = wasi_try_ok!( + state.fs + .create_fd(rights, rights, 0, 0, inode) + ); + + wasi_try_mem_ok!(ro_fd.write(memory, fd)); + wasi_try_ok!(super::state::write_ip_port(memory, ro_addr, addr.ip(), addr.port())); + + Ok(__WASI_ESUCCESS) +} + +/// ### `sock_connect()` +/// Initiate a connection on a socket to the specified address +/// +/// Polling the socket handle will wait for data to arrive or for +/// the socket status to change which can be queried via 'sock_status' +/// +/// Note: This is similar to `connect` in POSIX +/// +/// ## Parameters +/// +/// * `fd` - Socket descriptor +/// * `addr` - Address of the socket to connect to +pub fn sock_connect( + thread: &WasiThread, + sock: __wasi_fd_t, + addr: WasmPtr<__wasi_addr_port_t, M>, +) -> __wasi_errno_t { + debug!("wasi::sock_connect"); + + let addr = wasi_try!(super::state::read_ip_port(thread.memory(), addr)); + let addr = SocketAddr::new(addr.0, addr.1); + wasi_try!( + __sock_upgrade(thread, sock, __WASI_RIGHT_SOCK_CONNECT, |socket| { + socket.connect(thread.net(), addr) + }) + ); + __WASI_ESUCCESS +} + +/// ### `sock_recv()` +/// Receive a message from a socket. +/// Note: This is similar to `recv` in POSIX, though it also supports reading +/// the data into multiple buffers in the manner of `readv`. +/// +/// ## Parameters +/// +/// * `ri_data` - List of scatter/gather vectors to which to store data. +/// * `ri_flags` - Message flags. +/// +/// ## Return +/// +/// Number of bytes stored in ri_data and message flags. +pub fn sock_recv( + thread: &WasiThread, + sock: __wasi_fd_t, + ri_data: WasmPtr<__wasi_iovec_t, M>, + ri_data_len: M::Offset, + _ri_flags: __wasi_riflags_t, + ro_data_len: WasmPtr, + ro_flags: WasmPtr<__wasi_roflags_t, M>, +) -> Result<__wasi_errno_t, WasiError> { + debug!("wasi::sock_recv"); + + let memory = thread.memory(); + let iovs_arr = wasi_try_mem_ok!(ri_data.slice(memory, ri_data_len)); + + let bytes_read = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_RECV, |socket| { + socket.recv(memory, iovs_arr) + })); + let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| __WASI_EOVERFLOW)); + + wasi_try_mem_ok!(ro_flags.write(memory, 0)); + wasi_try_mem_ok!(ro_data_len.write(memory, bytes_read)); + + Ok(__WASI_ESUCCESS) +} + +/// ### `sock_recv_from()` +/// Receive a message and its peer address from a socket. +/// Note: This is similar to `recvfrom` in POSIX, though it also supports reading +/// the data into multiple buffers in the manner of `readv`. +/// +/// ## Parameters +/// +/// * `ri_data` - List of scatter/gather vectors to which to store data. +/// * `ri_flags` - Message flags. +/// +/// ## Return +/// +/// Number of bytes stored in ri_data and message flags. +pub fn sock_recv_from( + thread: &WasiThread, + sock: __wasi_fd_t, + ri_data: WasmPtr<__wasi_iovec_t, M>, + ri_data_len: M::Offset, + _ri_flags: __wasi_riflags_t, + ro_data_len: WasmPtr, + ro_flags: WasmPtr<__wasi_roflags_t, M>, + ro_addr: WasmPtr<__wasi_addr_port_t, M>, +) -> Result<__wasi_errno_t, WasiError> { + debug!("wasi::sock_recv_from"); + + let memory = thread.memory(); + let iovs_arr = wasi_try_mem_ok!(ri_data.slice(memory, ri_data_len)); + + let bytes_read = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_RECV_FROM, |socket| { + socket.recv_from(memory, iovs_arr, ro_addr) + })); + let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| __WASI_EOVERFLOW)); + + wasi_try_mem_ok!(ro_flags.write(memory, 0)); + wasi_try_mem_ok!(ro_data_len.write(memory, bytes_read)); + + Ok(__WASI_ESUCCESS) +} + +/// ### `sock_send()` +/// Send a message on a socket. +/// Note: This is similar to `send` in POSIX, though it also supports writing +/// the data from multiple buffers in the manner of `writev`. +/// +/// ## Parameters +/// +/// * `si_data` - List of scatter/gather vectors to which to retrieve data +/// * `si_flags` - Message flags. +/// +/// ## Return +/// +/// Number of bytes transmitted. +pub fn sock_send( + thread: &WasiThread, + sock: __wasi_fd_t, + si_data: WasmPtr<__wasi_ciovec_t, M>, + si_data_len: M::Offset, + _si_flags: __wasi_siflags_t, + ret_data_len: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + debug!("wasi::sock_send"); + + let memory = thread.memory(); + let iovs_arr = wasi_try_mem_ok!(si_data.slice(memory, si_data_len)); + + let bytes_written = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_SEND, |socket| { + socket.send(memory, iovs_arr) + })); + + let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); + wasi_try_mem_ok!(ret_data_len.write(memory, bytes_written)); + + Ok(__WASI_ESUCCESS) +} + +/// ### `sock_send_to()` +/// Send a message on a socket to a specific address. +/// Note: This is similar to `sendto` in POSIX, though it also supports writing +/// the data from multiple buffers in the manner of `writev`. +/// +/// ## Parameters +/// +/// * `si_data` - List of scatter/gather vectors to which to retrieve data +/// * `si_flags` - Message flags. +/// * `addr` - Address of the socket to send message to +/// +/// ## Return +/// +/// Number of bytes transmitted. +pub fn sock_send_to( + thread: &WasiThread, + sock: __wasi_fd_t, + si_data: WasmPtr<__wasi_ciovec_t, M>, + si_data_len: M::Offset, + _si_flags: __wasi_siflags_t, + addr: WasmPtr<__wasi_addr_port_t, M>, + ret_data_len: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + debug!("wasi::sock_send_to"); + + let memory = thread.memory(); + let iovs_arr = wasi_try_mem_ok!(si_data.slice(memory, si_data_len)); + + let bytes_written = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_SEND_TO, |socket| { + socket.send_to::(memory, iovs_arr, addr) + })); + + let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); + wasi_try_mem_ok!(ret_data_len.write(memory, bytes_written as M::Offset)); + + Ok(__WASI_ESUCCESS) +} + +/// ### `sock_send_file()` +/// Sends the entire contents of a file down a socket +/// +/// ## Parameters +/// +/// * `in_fd` - Open file that has the data to be transmitted +/// * `offset` - Offset into the file to start reading at +/// * `count` - Number of bytes to be sent +/// +/// ## Return +/// +/// Number of bytes transmitted. +pub unsafe fn sock_send_file( + thread: &WasiThread, + sock: __wasi_fd_t, + in_fd: __wasi_fd_t, + offset: __wasi_filesize_t, + mut count: __wasi_filesize_t, + ret_sent: WasmPtr<__wasi_filesize_t, M>, +) -> Result<__wasi_errno_t, WasiError> { + debug!("wasi::send_file"); + let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + + // Set the offset of the file + { + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try_ok!(fd_map.get_mut(&in_fd).ok_or(__WASI_EBADF)); + fd_entry.offset = offset as u64; + } + + // Enter a loop that will process all the data + let mut total_written: __wasi_filesize_t = 0; + while (count > 0) { + let mut buf = [0; 4096]; + let sub_count = count.min(4096); + count -= sub_count; + + let fd_entry = wasi_try_ok!(state.fs.get_fd(in_fd)); + let bytes_read = match in_fd { + __WASI_STDIN_FILENO => { + let mut guard = wasi_try_ok!( + inodes + .stdin_mut(&state.fs.fd_map) + .map_err(fs_error_into_wasi_err), + thread + ); + if let Some(ref mut stdin) = guard.deref_mut() { + wasi_try_ok!(stdin.read(&mut buf).map_err(map_io_err)) + } else { + return Ok(__WASI_EBADF); + } + } + __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => return Ok(__WASI_EINVAL), + _ => { + if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_READ) { + // TODO: figure out the error to return when lacking rights + return Ok(__WASI_EACCES); + } + + let offset = fd_entry.offset as usize; + let inode_idx = fd_entry.inode; + let inode = &inodes.arena[inode_idx]; + + let bytes_read = { + let mut guard = inode.write(); + match guard.deref_mut() { + Kind::File { handle, .. } => { + if let Some(handle) = handle { + wasi_try_ok!( + handle + .seek(std::io::SeekFrom::Start(offset as u64)) + .map_err(map_io_err), + thread + ); + wasi_try_ok!(handle.read(&mut buf).map_err(map_io_err)) + } else { + return Ok(__WASI_EINVAL); + } + } + Kind::Socket { socket } => { + wasi_try_ok!(socket.read(&mut buf).map_err(map_io_err)) + } + Kind::Pipe { pipe } => { + wasi_try_ok!(pipe.read(&mut buf).map_err(map_io_err)) + } + Kind::Dir { .. } | Kind::Root { .. } => { + return Ok(__WASI_EISDIR); + } + Kind::EventNotifications { .. } => { + return Ok(__WASI_EINVAL); + } + Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"), + Kind::Buffer { buffer } => { + let mut buf_read = &buffer[offset..]; + wasi_try_ok!(buf_read.read(&mut buf).map_err(map_io_err)) + } + } + }; + + // reborrow + let mut fd_map = state.fs.fd_map.write().unwrap(); + let fd_entry = wasi_try_ok!(fd_map.get_mut(&in_fd).ok_or(__WASI_EBADF)); + fd_entry.offset += bytes_read as u64; + + bytes_read + } + }; + + // Write it down to the socket + let bytes_written = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_SEND, |socket| { + let buf = (&buf[..]).to_vec(); + socket.send_bytes::(Bytes::from(buf)) + })); + total_written += bytes_written as u64; + } + + wasi_try_mem_ok!(ret_sent.write(memory, total_written as __wasi_filesize_t)); + + Ok(__WASI_ESUCCESS) +} + +/// ### `resolve()` +/// Resolves a hostname and a port to one or more IP addresses. +/// +/// Note: This is similar to `getaddrinfo` in POSIX +/// +/// When successful, the contents of the output buffer consist of a sequence of +/// IPv4 and/or IPv6 addresses. Each address entry consists of a addr_t object. +/// This function fills the output buffer as much as possible. +/// +/// ## Parameters +/// +/// * `host` - Host to resolve +/// * `port` - Port hint (zero if no hint is supplied) +/// * `addrs` - The buffer where addresses will be stored +/// +/// ## Return +/// +/// The number of IP addresses returned during the DNS resolution. +pub fn resolve( + thread: &WasiThread, + host: WasmPtr, + host_len: M::Offset, + port: u16, + addrs: WasmPtr<__wasi_addr_t, M>, + naddrs: M::Offset, + ret_naddrs: WasmPtr, +) -> __wasi_errno_t { + debug!("wasi::resolve"); + + let naddrs: usize = wasi_try!(naddrs.try_into().map_err(|_| __WASI_EINVAL)); + let memory = thread.memory(); + let host_str = unsafe { get_input_str!(memory, host, host_len) }; + let addrs = wasi_try_mem!(addrs.slice(memory, wasi_try!(to_offset::(naddrs)))); + + let port = if port > 0 { + Some(port) + } else { + None + }; + + let found_ips = wasi_try!( + thread.net() + .resolve(host_str.as_str(), port, None) + .map_err(net_error_into_wasi_err) + ); + + let mut idx = 0; + for found_ip in found_ips.iter().take(naddrs) { + super::state::write_ip(memory, addrs.index(idx).as_ptr::(), found_ip.clone()); + idx += 1; + } + + let idx: M::Offset = wasi_try!(idx.try_into().map_err(|_| __WASI_EOVERFLOW)); + wasi_try_mem!(ret_naddrs.write(memory, idx)); + + __WASI_ESUCCESS } diff --git a/lib/wasi/src/syscalls/wasi.rs b/lib/wasi/src/syscalls/wasi.rs new file mode 100644 index 00000000000..3889961db3f --- /dev/null +++ b/lib/wasi/src/syscalls/wasi.rs @@ -0,0 +1,405 @@ +#![deny(dead_code)] +use wasmer_wasi_types::*; +use wasmer::{Memory, WasmPtr, WasmSlice, MemorySize, Memory32}; +use crate::{WasiThread, WasiState, WasiError}; + +type MemoryType = Memory32; +type MemoryOffset = u32; + +pub(crate) fn args_get( + thread: &WasiThread, + argv: WasmPtr, MemoryType>, + argv_buf: WasmPtr, +) -> __wasi_errno_t { + super::args_get::(thread, argv, argv_buf) +} + +pub(crate) fn args_sizes_get( + thread: &WasiThread, + argc: WasmPtr, + argv_buf_size: WasmPtr, +) -> __wasi_errno_t { + super::args_sizes_get::(thread, argc, argv_buf_size) +} + +pub(crate) fn clock_res_get( + thread: &WasiThread, + clock_id: __wasi_clockid_t, + resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::clock_res_get::(thread, clock_id, resolution) +} + +pub(crate) fn clock_time_get( + thread: &WasiThread, + clock_id: __wasi_clockid_t, + precision: __wasi_timestamp_t, + time: WasmPtr<__wasi_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::clock_time_get::(thread, clock_id, precision, time) +} + +pub(crate) fn environ_get( + thread: &WasiThread, + environ: WasmPtr, MemoryType>, + environ_buf: WasmPtr, +) -> __wasi_errno_t { + super::environ_get::(thread, environ, environ_buf) +} + +pub(crate) fn environ_sizes_get( + thread: &WasiThread, + environ_count: WasmPtr, + environ_buf_size: WasmPtr, +) -> __wasi_errno_t { + super::environ_sizes_get::(thread, environ_count, environ_buf_size) +} + +pub(crate) fn fd_advise( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, + advice: __wasi_advice_t, +) -> __wasi_errno_t { + super::fd_advise(thread, fd, offset, len, advice) +} + +pub(crate) fn fd_allocate( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, +) -> __wasi_errno_t { + super::fd_allocate(thread, fd, offset, len) +} + +pub(crate) fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_close(thread, fd) +} + +pub(crate) fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_datasync(thread, fd) +} + +pub(crate) fn fd_fdstat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_fdstat_get::(thread, fd, buf_ptr) +} + +pub(crate) fn fd_fdstat_set_flags( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_fdflags_t, +) -> __wasi_errno_t { + super::fd_fdstat_set_flags(thread, fd, flags) +} + +pub(crate) fn fd_fdstat_set_rights( + thread: &WasiThread, + fd: __wasi_fd_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, +) -> __wasi_errno_t { + super::fd_fdstat_set_rights(thread, fd, fs_rights_base, fs_rights_inheriting) +} + +pub(crate) fn fd_filestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_filestat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_filestat_get::(thread, fd, buf) +} + +pub(crate) fn fd_filestat_set_size( + thread: &WasiThread, + fd: __wasi_fd_t, + st_size: __wasi_filesize_t, +) -> __wasi_errno_t { + super::fd_filestat_set_size(thread, fd, st_size) +} + +pub(crate) fn fd_filestat_set_times( + thread: &WasiThread, + fd: __wasi_fd_t, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fst_flags: __wasi_fstflags_t, +) -> __wasi_errno_t { + super::fd_filestat_set_times(thread, fd, st_atim, st_mtim, fst_flags) +} + +pub(crate) fn fd_pread( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_iovec_t, MemoryType>, + iovs_len: MemoryOffset, + offset: __wasi_filesize_t, + nread: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_pread::(thread, fd, iovs, iovs_len, offset, nread) +} + +pub(crate) fn fd_prestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_prestat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_prestat_get::(thread, fd, buf) +} + +pub(crate) fn fd_prestat_dir_name( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::fd_prestat_dir_name::(thread, fd, path, path_len) +} + +pub(crate) fn fd_pwrite( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, + iovs_len: MemoryOffset, + offset: __wasi_filesize_t, + nwritten: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_pwrite::(thread, fd, iovs, iovs_len, offset, nwritten) +} + +pub(crate) fn fd_read( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_iovec_t, MemoryType>, + iovs_len: MemoryOffset, + nread: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_read::(thread, fd, iovs, iovs_len, nread) +} + +pub(crate) fn fd_readdir( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr, + buf_len: MemoryOffset, + cookie: __wasi_dircookie_t, + bufused: WasmPtr, +) -> __wasi_errno_t { + super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) +} + +pub(crate) fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { + super::fd_renumber(thread, from, to) +} + +pub(crate) fn fd_seek( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filedelta_t, + whence: __wasi_whence_t, + newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_seek::(thread, fd, offset, whence, newoffset) +} + +pub(crate) fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_sync(thread, fd) +} + +pub(crate) fn fd_tell( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_tell::(thread, fd, offset) +} + +pub(crate) fn fd_write( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, + iovs_len: MemoryOffset, + nwritten: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_write::(thread, fd, iovs, iovs_len, nwritten) +} + +pub(crate) fn path_create_directory( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_create_directory::(thread, fd, path, path_len) +} + +pub(crate) fn path_filestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + buf: WasmPtr<__wasi_filestat_t, MemoryType>, +) -> __wasi_errno_t { + super::path_filestat_get::(thread, fd, flags, path, path_len, buf) +} + +pub(crate) fn path_filestat_set_times( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fst_flags: __wasi_fstflags_t, +) -> __wasi_errno_t { + super::path_filestat_set_times::(thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags) +} + +pub(crate) fn path_link( + thread: &WasiThread, + old_fd: __wasi_fd_t, + old_flags: __wasi_lookupflags_t, + old_path: WasmPtr, + old_path_len: MemoryOffset, + new_fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_link::(thread, old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) +} + +pub(crate) fn path_open( + thread: &WasiThread, + dirfd: __wasi_fd_t, + dirflags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + o_flags: __wasi_oflags_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, + fs_flags: __wasi_fdflags_t, + fd: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::path_open::(thread, dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) +} + +pub(crate) fn path_readlink( + thread: &WasiThread, + dir_fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, + buf: WasmPtr, + buf_len: MemoryOffset, + buf_used: WasmPtr, +) -> __wasi_errno_t { + super::path_readlink::(thread, dir_fd, path, path_len, buf, buf_len, buf_used) +} + +pub(crate) fn path_remove_directory( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_remove_directory::(thread, fd, path, path_len) +} + +pub(crate) fn path_rename( + thread: &WasiThread, + old_fd: __wasi_fd_t, + old_path: WasmPtr, + old_path_len: MemoryOffset, + new_fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_rename::(thread, old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) +} + +pub(crate) fn path_symlink( + thread: &WasiThread, + old_path: WasmPtr, + old_path_len: MemoryOffset, + fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_symlink::(thread, old_path, old_path_len, fd, new_path, new_path_len) +} + +pub(crate) fn path_unlink_file( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_unlink_file::(thread, fd, path, path_len) +} + +pub(crate) fn poll_oneoff( + thread: &WasiThread, + in_: WasmPtr<__wasi_subscription_t, MemoryType>, + out_: WasmPtr<__wasi_event_t, MemoryType>, + nsubscriptions: MemoryOffset, + nevents: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::poll_oneoff::(thread, in_, out_, nsubscriptions, nevents) +} + +pub(crate) fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { + super::proc_exit(thread, code) +} + +pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { + super::proc_raise(thread, sig) +} + +pub(crate) fn random_get( + thread: &WasiThread, + buf: WasmPtr, + buf_len: MemoryOffset +) -> __wasi_errno_t { + super::random_get::(thread, buf, buf_len) +} + +pub(crate) fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { + super::sched_yield(thread) +} + +pub(crate) fn sock_recv( + thread: &WasiThread, + sock: __wasi_fd_t, + ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, + ri_data_len: MemoryOffset, + ri_flags: __wasi_riflags_t, + ro_data_len: WasmPtr, + ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_recv::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags) +} + +pub(crate) fn sock_send( + thread: &WasiThread, + sock: __wasi_fd_t, + si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, + si_data_len: MemoryOffset, + si_flags: __wasi_siflags_t, + ret_data_len: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_send::(thread, sock, si_data, si_data_len, si_flags, ret_data_len) +} + +pub(crate) fn sock_shutdown( + thread: &WasiThread, + sock: __wasi_fd_t, + how: __wasi_sdflags_t, +) -> __wasi_errno_t { + super::sock_shutdown(thread, sock, how) +} diff --git a/lib/wasi/src/syscalls/wasix32.rs b/lib/wasi/src/syscalls/wasix32.rs new file mode 100644 index 00000000000..1fe15d9beed --- /dev/null +++ b/lib/wasi/src/syscalls/wasix32.rs @@ -0,0 +1,986 @@ +#![deny(dead_code)] +use wasmer_wasi_types::*; +use wasmer::{Memory, WasmPtr, WasmSlice, MemorySize, Memory32}; +use crate::{WasiThread, WasiState, WasiError}; + +type MemoryType = Memory32; +type MemoryOffset = u32; + +pub(crate) fn args_get( + thread: &WasiThread, + argv: WasmPtr, MemoryType>, + argv_buf: WasmPtr, +) -> __wasi_errno_t { + super::args_get::(thread, argv, argv_buf) +} + +pub(crate) fn args_sizes_get( + thread: &WasiThread, + argc: WasmPtr, + argv_buf_size: WasmPtr, +) -> __wasi_errno_t { + super::args_sizes_get::(thread, argc, argv_buf_size) +} + +pub(crate) fn clock_res_get( + thread: &WasiThread, + clock_id: __wasi_clockid_t, + resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::clock_res_get::(thread, clock_id, resolution) +} + +pub(crate) fn clock_time_get( + thread: &WasiThread, + clock_id: __wasi_clockid_t, + precision: __wasi_timestamp_t, + time: WasmPtr<__wasi_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::clock_time_get::(thread, clock_id, precision, time) +} + +pub(crate) fn environ_get( + thread: &WasiThread, + environ: WasmPtr, MemoryType>, + environ_buf: WasmPtr, +) -> __wasi_errno_t { + super::environ_get::(thread, environ, environ_buf) +} + +pub(crate) fn environ_sizes_get( + thread: &WasiThread, + environ_count: WasmPtr, + environ_buf_size: WasmPtr, +) -> __wasi_errno_t { + super::environ_sizes_get::(thread, environ_count, environ_buf_size) +} + +pub(crate) fn fd_advise( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, + advice: __wasi_advice_t, +) -> __wasi_errno_t { + super::fd_advise(thread, fd, offset, len, advice) +} + +pub(crate) fn fd_allocate( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, +) -> __wasi_errno_t { + super::fd_allocate(thread, fd, offset, len) +} + +pub(crate) fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_close(thread, fd) +} + +pub(crate) fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_datasync(thread, fd) +} + +pub(crate) fn fd_fdstat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_fdstat_get::(thread, fd, buf_ptr) +} + +pub(crate) fn fd_fdstat_set_flags( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_fdflags_t, +) -> __wasi_errno_t { + super::fd_fdstat_set_flags(thread, fd, flags) +} + +pub(crate) fn fd_fdstat_set_rights( + thread: &WasiThread, + fd: __wasi_fd_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, +) -> __wasi_errno_t { + super::fd_fdstat_set_rights(thread, fd, fs_rights_base, fs_rights_inheriting) +} + +pub(crate) fn fd_filestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_filestat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_filestat_get::(thread, fd, buf) +} + +pub(crate) fn fd_filestat_set_size( + thread: &WasiThread, + fd: __wasi_fd_t, + st_size: __wasi_filesize_t, +) -> __wasi_errno_t { + super::fd_filestat_set_size(thread, fd, st_size) +} + +pub(crate) fn fd_filestat_set_times( + thread: &WasiThread, + fd: __wasi_fd_t, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fst_flags: __wasi_fstflags_t, +) -> __wasi_errno_t { + super::fd_filestat_set_times(thread, fd, st_atim, st_mtim, fst_flags) +} + +pub(crate) fn fd_pread( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_iovec_t, MemoryType>, + iovs_len: MemoryOffset, + offset: __wasi_filesize_t, + nread: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_pread::(thread, fd, iovs, iovs_len, offset, nread) +} + +pub(crate) fn fd_prestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_prestat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_prestat_get::(thread, fd, buf) +} + +pub(crate) fn fd_prestat_dir_name( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::fd_prestat_dir_name::(thread, fd, path, path_len) +} + +pub(crate) fn fd_pwrite( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, + iovs_len: MemoryOffset, + offset: __wasi_filesize_t, + nwritten: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_pwrite::(thread, fd, iovs, iovs_len, offset, nwritten) +} + +pub(crate) fn fd_read( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_iovec_t, MemoryType>, + iovs_len: MemoryOffset, + nread: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_read::(thread, fd, iovs, iovs_len, nread) +} + +pub(crate) fn fd_readdir( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr, + buf_len: MemoryOffset, + cookie: __wasi_dircookie_t, + bufused: WasmPtr, +) -> __wasi_errno_t { + super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) +} + +pub(crate) fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { + super::fd_renumber(thread, from, to) +} + +pub(crate) fn fd_seek( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filedelta_t, + whence: __wasi_whence_t, + newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_seek::(thread, fd, offset, whence, newoffset) +} + +pub(crate) fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_sync(thread, fd) +} + +pub(crate) fn fd_tell( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_tell::(thread, fd, offset) +} + +pub(crate) fn fd_write( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, + iovs_len: MemoryOffset, + nwritten: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_write::(thread, fd, iovs, iovs_len, nwritten) +} + +pub(crate) fn path_create_directory( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_create_directory::(thread, fd, path, path_len) +} + +pub(crate) fn path_filestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + buf: WasmPtr<__wasi_filestat_t, MemoryType>, +) -> __wasi_errno_t { + super::path_filestat_get::(thread, fd, flags, path, path_len, buf) +} + +pub(crate) fn path_filestat_set_times( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fst_flags: __wasi_fstflags_t, +) -> __wasi_errno_t { + super::path_filestat_set_times::(thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags) +} + +pub(crate) fn path_link( + thread: &WasiThread, + old_fd: __wasi_fd_t, + old_flags: __wasi_lookupflags_t, + old_path: WasmPtr, + old_path_len: MemoryOffset, + new_fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_link::(thread, old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) +} + +pub(crate) fn path_open( + thread: &WasiThread, + dirfd: __wasi_fd_t, + dirflags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + o_flags: __wasi_oflags_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, + fs_flags: __wasi_fdflags_t, + fd: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::path_open::(thread, dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) +} + +pub(crate) fn path_readlink( + thread: &WasiThread, + dir_fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, + buf: WasmPtr, + buf_len: MemoryOffset, + buf_used: WasmPtr, +) -> __wasi_errno_t { + super::path_readlink::(thread, dir_fd, path, path_len, buf, buf_len, buf_used) +} + +pub(crate) fn path_remove_directory( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_remove_directory::(thread, fd, path, path_len) +} + +pub(crate) fn path_rename( + thread: &WasiThread, + old_fd: __wasi_fd_t, + old_path: WasmPtr, + old_path_len: MemoryOffset, + new_fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_rename::(thread, old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) +} + +pub(crate) fn path_symlink( + thread: &WasiThread, + old_path: WasmPtr, + old_path_len: MemoryOffset, + fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_symlink::(thread, old_path, old_path_len, fd, new_path, new_path_len) +} + +pub(crate) fn path_unlink_file( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_unlink_file::(thread, fd, path, path_len) +} + +pub(crate) fn poll_oneoff( + thread: &WasiThread, + in_: WasmPtr<__wasi_subscription_t, MemoryType>, + out_: WasmPtr<__wasi_event_t, MemoryType>, + nsubscriptions: MemoryOffset, + nevents: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::poll_oneoff::(thread, in_, out_, nsubscriptions, nevents) +} + +pub(crate) fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { + super::proc_exit(thread, code) +} + +pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { + super::proc_raise(thread, sig) +} + +pub(crate) fn random_get( + thread: &WasiThread, + buf: WasmPtr, + buf_len: MemoryOffset +) -> __wasi_errno_t { + super::random_get::(thread, buf, buf_len) +} + +pub(crate) fn fd_dup( + thread: &WasiThread, + fd: __wasi_fd_t, + ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_dup::(thread, fd, ret_fd) +} + +pub(crate) fn fd_event( + thread: &WasiThread, + initial_val: u64, + flags: __wasi_eventfdflags, + ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_event(thread, initial_val, flags, ret_fd) +} + +pub(crate) fn fd_pipe( + thread: &WasiThread, + ro_fd1: WasmPtr<__wasi_fd_t, MemoryType>, + ro_fd2: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_pipe::(thread, ro_fd1, ro_fd2) +} + +pub(crate) fn tty_get( + thread: &WasiThread, + tty_state: WasmPtr<__wasi_tty_t, MemoryType>, +) -> __wasi_errno_t { + super::tty_get::(thread, tty_state) +} + +pub(crate) fn tty_set( + thread: &WasiThread, + tty_state: WasmPtr<__wasi_tty_t, MemoryType>, +) -> __wasi_errno_t { + super::tty_set::(thread, tty_state) +} + +pub(crate) fn getcwd( + thread: &WasiThread, + path: WasmPtr, + path_len: WasmPtr, +) -> __wasi_errno_t { + super::getcwd::(thread, path, path_len) +} + +pub(crate) fn chdir( + thread: &WasiThread, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::chdir::(thread, path, path_len) +} + +pub(crate) fn thread_spawn( + thread: &WasiThread, + method: WasmPtr, + method_len: MemoryOffset, + user_data: u64, + reactor: __wasi_bool_t, + ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, +) -> __wasi_errno_t { + super::thread_spawn::(thread, method, method_len, user_data, reactor, ret_tid) +} + +pub(crate) fn thread_sleep( + thread: &WasiThread, + duration: __wasi_timestamp_t, +) -> Result<__wasi_errno_t, WasiError> { + super::thread_sleep(thread, duration) +} + +pub(crate) fn thread_id( + thread: &WasiThread, + ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, +) -> __wasi_errno_t { + super::thread_id::(thread, ret_tid) +} + +pub(crate) fn thread_join( + thread: &WasiThread, + tid: __wasi_tid_t, +) -> __wasi_errno_t { + super::thread_join(thread, tid) +} + +pub(crate) fn thread_parallelism( + thread: &WasiThread, + ret_parallelism: WasmPtr, +) -> __wasi_errno_t { + super::thread_parallelism::(thread, ret_parallelism) +} + +pub(crate) fn thread_exit( + thread: &WasiThread, + exitcode: __wasi_exitcode_t, +) -> Result<__wasi_errno_t, WasiError> { + super::thread_exit(thread, exitcode) +} + +pub(crate) fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { + super::sched_yield(thread) +} + +pub(crate) fn getpid( + thread: &WasiThread, + ret_pid: WasmPtr<__wasi_pid_t, MemoryType>, +) -> __wasi_errno_t { + super::getpid::(thread, ret_pid) +} + +pub(crate) fn bus_spawn_local( + thread: &WasiThread, + name: WasmPtr, + name_len: MemoryOffset, + chroot: __wasi_bool_t, + args: WasmPtr, + args_len: MemoryOffset, + preopen: WasmPtr, + preopen_len: MemoryOffset, + stdin: __wasi_stdiomode_t, + stdout: __wasi_stdiomode_t, + stderr: __wasi_stdiomode_t, + working_dir: WasmPtr, + working_dir_len: MemoryOffset, + ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, +) -> __wasi_errno_t { + super::bus_spawn_local::(thread, name, name_len, chroot, args, args_len, preopen, preopen_len, stdin, stdout, stderr, working_dir, working_dir_len, ret_handles) +} + +pub(crate) fn bus_spawn_remote( + thread: &WasiThread, + name: WasmPtr, + name_len: MemoryOffset, + chroot: __wasi_bool_t, + args: WasmPtr, + args_len: MemoryOffset, + preopen: WasmPtr, + preopen_len: MemoryOffset, + working_dir: WasmPtr, + working_dir_len: MemoryOffset, + stdin: __wasi_stdiomode_t, + stdout: __wasi_stdiomode_t, + stderr: __wasi_stdiomode_t, + instance: WasmPtr, + instance_len: MemoryOffset, + token: WasmPtr, + token_len: MemoryOffset, + ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, +) -> __wasi_errno_t { + super::bus_spawn_remote::(thread, name, name_len, chroot, args, args_len, preopen, preopen_len, working_dir, working_dir_len, stdin, stdout, stderr, instance, instance_len, token, token_len, ret_handles) +} + +pub(crate) fn bus_close( + thread: &WasiThread, + bid: __wasi_bid_t, +) -> __wasi_errno_t { + super::bus_close(thread, bid) +} + +pub(crate) fn bus_invoke( + thread: &WasiThread, + bid: __wasi_bid_t, + cid: WasmPtr<__wasi_option_cid_t, MemoryType>, + keep_alive: __wasi_bool_t, + topic: WasmPtr, + topic_len: MemoryOffset, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: MemoryOffset, + ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, +) -> __wasi_errno_t { + super::bus_invoke::(thread, bid, cid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid) +} + +pub(crate) fn bus_fault( + thread: &WasiThread, + cid: __wasi_cid_t, + fault: __bus_errno_t, +) -> __wasi_errno_t { + super::bus_fault(thread, cid, fault) +} + +pub(crate) fn bus_drop( + thread: &WasiThread, + cid: __wasi_cid_t, +) -> __wasi_errno_t { + super::bus_drop(thread, cid) +} + +pub(crate) fn bus_reply( + thread: &WasiThread, + cid: __wasi_cid_t, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: MemoryOffset, +) -> __wasi_errno_t { + super::bus_reply::(thread, cid, format, buf, buf_len) +} + +pub(crate) fn bus_callback( + thread: &WasiThread, + cid: __wasi_cid_t, + topic: WasmPtr, + topic_len: MemoryOffset, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: MemoryOffset, +) -> __wasi_errno_t { + super::bus_callback::(thread, cid, topic, topic_len, format, buf, buf_len) +} + +pub(crate) fn bus_listen( + thread: &WasiThread, + parent: WasmPtr<__wasi_option_cid_t, MemoryType>, + topic: WasmPtr, + topic_len: MemoryOffset, +) -> __wasi_errno_t { + super::bus_listen::(thread, parent, topic, topic_len) +} + +pub(crate) fn bus_poll( + thread: &WasiThread, + bid: WasmPtr<__wasi_option_bid_t, MemoryType>, + timeout: WasmPtr<__wasi_timestamp_t, MemoryType>, + events: WasmPtr, + nevents: MemoryOffset, + ret_nevents: WasmPtr, +) -> __wasi_errno_t { + super::bus_poll::(thread, bid, timeout, events, nevents, ret_nevents) +} + +pub(crate) fn bus_poll_data( + thread: &WasiThread, + bid: WasmPtr<__wasi_option_bid_t, MemoryType>, + timeout: WasmPtr<__wasi_timestamp_t, MemoryType>, + topic: WasmPtr, + topic_len: MemoryOffset, + buf: WasmPtr, + buf_len: MemoryOffset, + ret_evt: WasmPtr<__wasi_busevent_data_t, MemoryType>, +) -> __wasi_errno_t { + super::bus_poll_data::(thread, bid, timeout, topic, topic_len, buf, buf_len, ret_evt) +} + +pub(crate) fn port_bridge( + thread: &WasiThread, + network: WasmPtr, + network_len: MemoryOffset, + token: WasmPtr, + token_len: MemoryOffset, + security: __wasi_streamsecurity_t, +) -> __wasi_errno_t { + super::port_bridge::(thread, network, network_len, token, token_len, security) +} + +pub(crate) fn port_unbridge( + thread: &WasiThread, +) -> __wasi_errno_t { + super::port_unbridge(thread) +} + +pub(crate) fn port_dhcp_acquire( + thread: &WasiThread, +) -> __wasi_errno_t { + super::port_dhcp_acquire(thread) +} + +pub(crate) fn port_addr_add( + thread: &WasiThread, + addr: WasmPtr<__wasi_cidr_t, MemoryType>, +) -> __wasi_errno_t { + super::port_addr_add::(thread, addr) +} + +pub(crate) fn port_addr_remove( + thread: &WasiThread, + addr: WasmPtr<__wasi_addr_t, MemoryType>, +) -> __wasi_errno_t { + super::port_addr_remove::(thread, addr) +} + +pub(crate) fn port_addr_clear( + thread: &WasiThread, +) -> __wasi_errno_t { + super::port_addr_clear(thread) +} + +pub(crate) fn port_addr_list( + thread: &WasiThread, + addrs: WasmPtr<__wasi_cidr_t, MemoryType>, + naddrs: WasmPtr, +) -> __wasi_errno_t { + super::port_addr_list::(thread, addrs, naddrs) +} + +pub(crate) fn port_mac( + thread: &WasiThread, + ret_mac: WasmPtr<__wasi_hardwareaddress_t, MemoryType>, +) -> __wasi_errno_t { + super::port_mac::(thread, ret_mac) +} + +pub(crate) fn port_gateway_set( + thread: &WasiThread, + ip: WasmPtr<__wasi_addr_t, MemoryType>, +) -> __wasi_errno_t { + super::port_gateway_set::(thread, ip) +} + +pub(crate) fn port_route_add( + thread: &WasiThread, + cidr: WasmPtr<__wasi_cidr_t, MemoryType>, + via_router: WasmPtr<__wasi_addr_t, MemoryType>, + preferred_until: WasmPtr<__wasi_option_timestamp_t, MemoryType>, + expires_at: WasmPtr<__wasi_option_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::port_route_add::(thread, cidr, via_router, preferred_until, expires_at) +} + +pub(crate) fn port_route_remove( + thread: &WasiThread, + ip: WasmPtr<__wasi_addr_t, MemoryType>, +) -> __wasi_errno_t { + super::port_route_remove::(thread, ip) +} + +pub(crate) fn port_route_clear( + thread: &WasiThread, +) -> __wasi_errno_t { + super::port_route_clear(thread) +} + +pub(crate) fn port_route_list( + thread: &WasiThread, + routes: WasmPtr<__wasi_route_t, MemoryType>, + nroutes: WasmPtr, +) -> __wasi_errno_t { + super::port_route_list::(thread, routes, nroutes) +} + +pub(crate) fn ws_connect( + thread: &WasiThread, + url: WasmPtr, + url_len: MemoryOffset, + ret_sock: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::ws_connect::(thread, url, url_len, ret_sock) +} + +pub(crate) fn http_request( + thread: &WasiThread, + url: WasmPtr, + url_len: MemoryOffset, + method: WasmPtr, + method_len: MemoryOffset, + headers: WasmPtr, + headers_len: MemoryOffset, + gzip: __wasi_bool_t, + ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, +) -> __wasi_errno_t { + super::http_request::(thread, url, url_len, method, method_len, headers, headers_len, gzip, ret_handles) +} + +pub(crate) fn http_status( + thread: &WasiThread, + sock: __wasi_fd_t, + status: WasmPtr<__wasi_http_status_t, MemoryType>, + status_text: WasmPtr, + status_text_len: WasmPtr, + headers: WasmPtr, + headers_len: WasmPtr, +) -> __wasi_errno_t { + super::http_status::(thread, sock, status) +} + +pub(crate) fn sock_status( + thread: &WasiThread, + sock: __wasi_fd_t, + ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType> +) -> __wasi_errno_t { + super::sock_status::(thread, sock, ret_status) +} + +pub(crate) fn sock_addr_local( + thread: &WasiThread, + sock: __wasi_fd_t, + ret_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_addr_local::(thread, sock, ret_addr) +} + +pub(crate) fn sock_addr_peer( + thread: &WasiThread, + sock: __wasi_fd_t, + ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_addr_peer::(thread, sock, ro_addr) +} + +pub(crate) fn sock_open( + thread: &WasiThread, + af: __wasi_addressfamily_t, + ty: __wasi_socktype_t, + pt: __wasi_sockproto_t, + ro_sock: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_open::(thread, af, ty, pt, ro_sock) +} + +pub(crate) fn sock_set_opt_flag( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + flag: __wasi_bool_t, +) -> __wasi_errno_t { + super::sock_set_opt_flag(thread, sock, opt, flag) +} + +pub(crate) fn sock_get_opt_flag( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_flag: WasmPtr<__wasi_bool_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_get_opt_flag::(thread, sock, opt, ret_flag) +} + +pub fn sock_set_opt_time( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_set_opt_time(thread, sock, opt, time) +} + +pub fn sock_get_opt_time( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_get_opt_time(thread, sock, opt, ret_time) +} + +pub fn sock_set_opt_size( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + size: __wasi_filesize_t, +) -> __wasi_errno_t { + super::sock_set_opt_size(thread, sock, opt, size) +} + +pub fn sock_get_opt_size( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_size: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_get_opt_size(thread, sock, opt, ret_size) +} + +pub(crate) fn sock_join_multicast_v4( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, + iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_join_multicast_v4::(thread, sock, multiaddr, iface) +} + +pub(crate) fn sock_leave_multicast_v4( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, + iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_leave_multicast_v4::(thread, sock, multiaddr, iface) +} + +pub(crate) fn sock_join_multicast_v6( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, + iface: u32, +) -> __wasi_errno_t { + super::sock_join_multicast_v6::(thread, sock, multiaddr, iface) +} + +pub(crate) fn sock_leave_multicast_v6( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, + iface: u32, +) -> __wasi_errno_t { + super::sock_leave_multicast_v6::(thread, sock, multiaddr, iface) +} + +pub(crate) fn sock_bind( + thread: &WasiThread, + sock: __wasi_fd_t, + addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_bind::(thread, sock, addr) +} + +pub(crate) fn sock_listen( + thread: &WasiThread, + sock: __wasi_fd_t, + backlog: MemoryOffset, +) -> __wasi_errno_t { + super::sock_listen::(thread, sock, backlog) +} + +pub(crate) fn sock_accept( + thread: &WasiThread, + sock: __wasi_fd_t, + fd_flags: __wasi_fdflags_t, + ro_fd: WasmPtr<__wasi_fd_t, MemoryType>, + ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_accept::(thread, sock, fd_flags, ro_fd, ro_addr) +} + +pub(crate) fn sock_connect( + thread: &WasiThread, + sock: __wasi_fd_t, + addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_connect::(thread, sock, addr) +} + +pub(crate) fn sock_recv( + thread: &WasiThread, + sock: __wasi_fd_t, + ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, + ri_data_len: MemoryOffset, + ri_flags: __wasi_riflags_t, + ro_data_len: WasmPtr, + ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_recv::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags) +} + +pub(crate) fn sock_recv_from( + thread: &WasiThread, + sock: __wasi_fd_t, + ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, + ri_data_len: MemoryOffset, + ri_flags: __wasi_riflags_t, + ro_data_len: WasmPtr, + ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, + ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_recv_from::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags, ro_addr) +} + +pub(crate) fn sock_send( + thread: &WasiThread, + sock: __wasi_fd_t, + si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, + si_data_len: MemoryOffset, + si_flags: __wasi_siflags_t, + ret_data_len: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_send::(thread, sock, si_data, si_data_len, si_flags, ret_data_len) +} + +pub(crate) fn sock_send_to( + thread: &WasiThread, + sock: __wasi_fd_t, + si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, + si_data_len: MemoryOffset, + si_flags: __wasi_siflags_t, + addr: WasmPtr<__wasi_addr_port_t, MemoryType>, + ret_data_len: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_send_to::(thread, sock, si_data, si_data_len, si_flags, addr, ret_data_len) +} + +pub(crate) fn sock_send_file( + thread: &WasiThread, + out_fd: __wasi_fd_t, + in_fd: __wasi_fd_t, + offset: __wasi_filesize_t, + count: __wasi_filesize_t, + ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + unsafe { + super::sock_send_file::(thread, out_fd, in_fd, offset, count, ret_sent) + } +} + +pub(crate) fn sock_shutdown( + thread: &WasiThread, + sock: __wasi_fd_t, + how: __wasi_sdflags_t, +) -> __wasi_errno_t { + super::sock_shutdown(thread, sock, how) +} + +pub(crate) fn resolve( + thread: &WasiThread, + host: WasmPtr, + host_len: MemoryOffset, + port: u16, + ips: WasmPtr<__wasi_addr_t, MemoryType>, + nips: MemoryOffset, + ret_nips: WasmPtr, +) -> __wasi_errno_t { + super::resolve::(thread, host, host_len, port, ips, nips, ret_nips) +} diff --git a/lib/wasi/src/syscalls/wasix64.rs b/lib/wasi/src/syscalls/wasix64.rs new file mode 100644 index 00000000000..0ef06d914a5 --- /dev/null +++ b/lib/wasi/src/syscalls/wasix64.rs @@ -0,0 +1,986 @@ +#![deny(dead_code)] +use wasmer_wasi_types::*; +use wasmer::{Memory, WasmPtr, WasmSlice, MemorySize, Memory64}; +use crate::{WasiThread, WasiState, WasiError}; + +type MemoryType = Memory64; +type MemoryOffset = u64; + +pub(crate) fn args_get( + thread: &WasiThread, + argv: WasmPtr, MemoryType>, + argv_buf: WasmPtr, +) -> __wasi_errno_t { + super::args_get::(thread, argv, argv_buf) +} + +pub(crate) fn args_sizes_get( + thread: &WasiThread, + argc: WasmPtr, + argv_buf_size: WasmPtr, +) -> __wasi_errno_t { + super::args_sizes_get::(thread, argc, argv_buf_size) +} + +pub(crate) fn clock_res_get( + thread: &WasiThread, + clock_id: __wasi_clockid_t, + resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::clock_res_get::(thread, clock_id, resolution) +} + +pub(crate) fn clock_time_get( + thread: &WasiThread, + clock_id: __wasi_clockid_t, + precision: __wasi_timestamp_t, + time: WasmPtr<__wasi_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::clock_time_get::(thread, clock_id, precision, time) +} + +pub(crate) fn environ_get( + thread: &WasiThread, + environ: WasmPtr, MemoryType>, + environ_buf: WasmPtr, +) -> __wasi_errno_t { + super::environ_get::(thread, environ, environ_buf) +} + +pub(crate) fn environ_sizes_get( + thread: &WasiThread, + environ_count: WasmPtr, + environ_buf_size: WasmPtr, +) -> __wasi_errno_t { + super::environ_sizes_get::(thread, environ_count, environ_buf_size) +} + +pub(crate) fn fd_advise( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, + advice: __wasi_advice_t, +) -> __wasi_errno_t { + super::fd_advise(thread, fd, offset, len, advice) +} + +pub(crate) fn fd_allocate( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, +) -> __wasi_errno_t { + super::fd_allocate(thread, fd, offset, len) +} + +pub(crate) fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_close(thread, fd) +} + +pub(crate) fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_datasync(thread, fd) +} + +pub(crate) fn fd_fdstat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_fdstat_get::(thread, fd, buf_ptr) +} + +pub(crate) fn fd_fdstat_set_flags( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_fdflags_t, +) -> __wasi_errno_t { + super::fd_fdstat_set_flags(thread, fd, flags) +} + +pub(crate) fn fd_fdstat_set_rights( + thread: &WasiThread, + fd: __wasi_fd_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, +) -> __wasi_errno_t { + super::fd_fdstat_set_rights(thread, fd, fs_rights_base, fs_rights_inheriting) +} + +pub(crate) fn fd_filestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_filestat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_filestat_get::(thread, fd, buf) +} + +pub(crate) fn fd_filestat_set_size( + thread: &WasiThread, + fd: __wasi_fd_t, + st_size: __wasi_filesize_t, +) -> __wasi_errno_t { + super::fd_filestat_set_size(thread, fd, st_size) +} + +pub(crate) fn fd_filestat_set_times( + thread: &WasiThread, + fd: __wasi_fd_t, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fst_flags: __wasi_fstflags_t, +) -> __wasi_errno_t { + super::fd_filestat_set_times(thread, fd, st_atim, st_mtim, fst_flags) +} + +pub(crate) fn fd_pread( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_iovec_t, MemoryType>, + iovs_len: MemoryOffset, + offset: __wasi_filesize_t, + nread: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_pread::(thread, fd, iovs, iovs_len, offset, nread) +} + +pub(crate) fn fd_prestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr<__wasi_prestat_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_prestat_get::(thread, fd, buf) +} + +pub(crate) fn fd_prestat_dir_name( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::fd_prestat_dir_name::(thread, fd, path, path_len) +} + +pub(crate) fn fd_pwrite( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, + iovs_len: MemoryOffset, + offset: __wasi_filesize_t, + nwritten: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_pwrite::(thread, fd, iovs, iovs_len, offset, nwritten) +} + +pub(crate) fn fd_read( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_iovec_t, MemoryType>, + iovs_len: MemoryOffset, + nread: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_read::(thread, fd, iovs, iovs_len, nread) +} + +pub(crate) fn fd_readdir( + thread: &WasiThread, + fd: __wasi_fd_t, + buf: WasmPtr, + buf_len: MemoryOffset, + cookie: __wasi_dircookie_t, + bufused: WasmPtr, +) -> __wasi_errno_t { + super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) +} + +pub(crate) fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { + super::fd_renumber(thread, from, to) +} + +pub(crate) fn fd_seek( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: __wasi_filedelta_t, + whence: __wasi_whence_t, + newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_seek::(thread, fd, offset, whence, newoffset) +} + +pub(crate) fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_sync(thread, fd) +} + +pub(crate) fn fd_tell( + thread: &WasiThread, + fd: __wasi_fd_t, + offset: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_tell::(thread, fd, offset) +} + +pub(crate) fn fd_write( + thread: &WasiThread, + fd: __wasi_fd_t, + iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, + iovs_len: MemoryOffset, + nwritten: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::fd_write::(thread, fd, iovs, iovs_len, nwritten) +} + +pub(crate) fn path_create_directory( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_create_directory::(thread, fd, path, path_len) +} + +pub(crate) fn path_filestat_get( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + buf: WasmPtr<__wasi_filestat_t, MemoryType>, +) -> __wasi_errno_t { + super::path_filestat_get::(thread, fd, flags, path, path_len, buf) +} + +pub(crate) fn path_filestat_set_times( + thread: &WasiThread, + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fst_flags: __wasi_fstflags_t, +) -> __wasi_errno_t { + super::path_filestat_set_times::(thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags) +} + +pub(crate) fn path_link( + thread: &WasiThread, + old_fd: __wasi_fd_t, + old_flags: __wasi_lookupflags_t, + old_path: WasmPtr, + old_path_len: MemoryOffset, + new_fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_link::(thread, old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) +} + +pub(crate) fn path_open( + thread: &WasiThread, + dirfd: __wasi_fd_t, + dirflags: __wasi_lookupflags_t, + path: WasmPtr, + path_len: MemoryOffset, + o_flags: __wasi_oflags_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, + fs_flags: __wasi_fdflags_t, + fd: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::path_open::(thread, dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) +} + +pub(crate) fn path_readlink( + thread: &WasiThread, + dir_fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, + buf: WasmPtr, + buf_len: MemoryOffset, + buf_used: WasmPtr, +) -> __wasi_errno_t { + super::path_readlink::(thread, dir_fd, path, path_len, buf, buf_len, buf_used) +} + +pub(crate) fn path_remove_directory( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_remove_directory::(thread, fd, path, path_len) +} + +pub(crate) fn path_rename( + thread: &WasiThread, + old_fd: __wasi_fd_t, + old_path: WasmPtr, + old_path_len: MemoryOffset, + new_fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_rename::(thread, old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) +} + +pub(crate) fn path_symlink( + thread: &WasiThread, + old_path: WasmPtr, + old_path_len: MemoryOffset, + fd: __wasi_fd_t, + new_path: WasmPtr, + new_path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_symlink::(thread, old_path, old_path_len, fd, new_path, new_path_len) +} + +pub(crate) fn path_unlink_file( + thread: &WasiThread, + fd: __wasi_fd_t, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::path_unlink_file::(thread, fd, path, path_len) +} + +pub(crate) fn poll_oneoff( + thread: &WasiThread, + in_: WasmPtr<__wasi_subscription_t, MemoryType>, + out_: WasmPtr<__wasi_event_t, MemoryType>, + nsubscriptions: MemoryOffset, + nevents: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::poll_oneoff::(thread, in_, out_, nsubscriptions, nevents) +} + +pub(crate) fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { + super::proc_exit(thread, code) +} + +pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { + super::proc_raise(thread, sig) +} + +pub(crate) fn random_get( + thread: &WasiThread, + buf: WasmPtr, + buf_len: MemoryOffset +) -> __wasi_errno_t { + super::random_get::(thread, buf, buf_len) +} + +pub(crate) fn fd_dup( + thread: &WasiThread, + fd: __wasi_fd_t, + ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_dup::(thread, fd, ret_fd) +} + +pub(crate) fn fd_event( + thread: &WasiThread, + initial_val: u64, + flags: __wasi_eventfdflags, + ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_event(thread, initial_val, flags, ret_fd) +} + +pub(crate) fn fd_pipe( + thread: &WasiThread, + ro_fd1: WasmPtr<__wasi_fd_t, MemoryType>, + ro_fd2: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::fd_pipe::(thread, ro_fd1, ro_fd2) +} + +pub(crate) fn tty_get( + thread: &WasiThread, + tty_state: WasmPtr<__wasi_tty_t, MemoryType>, +) -> __wasi_errno_t { + super::tty_get::(thread, tty_state) +} + +pub(crate) fn tty_set( + thread: &WasiThread, + tty_state: WasmPtr<__wasi_tty_t, MemoryType>, +) -> __wasi_errno_t { + super::tty_set::(thread, tty_state) +} + +pub(crate) fn getcwd( + thread: &WasiThread, + path: WasmPtr, + path_len: WasmPtr, +) -> __wasi_errno_t { + super::getcwd::(thread, path, path_len) +} + +pub(crate) fn chdir( + thread: &WasiThread, + path: WasmPtr, + path_len: MemoryOffset, +) -> __wasi_errno_t { + super::chdir::(thread, path, path_len) +} + +pub(crate) fn thread_spawn( + thread: &WasiThread, + method: WasmPtr, + method_len: MemoryOffset, + user_data: u64, + reactor: __wasi_bool_t, + ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, +) -> __wasi_errno_t { + super::thread_spawn::(thread, method, method_len, user_data, reactor, ret_tid) +} + +pub(crate) fn thread_sleep( + thread: &WasiThread, + duration: __wasi_timestamp_t, +) -> Result<__wasi_errno_t, WasiError> { + super::thread_sleep(thread, duration) +} + +pub(crate) fn thread_id( + thread: &WasiThread, + ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, +) -> __wasi_errno_t { + super::thread_id::(thread, ret_tid) +} + +pub(crate) fn thread_join( + thread: &WasiThread, + tid: __wasi_tid_t, +) -> __wasi_errno_t { + super::thread_join(thread, tid) +} + +pub(crate) fn thread_parallelism( + thread: &WasiThread, + ret_parallelism: WasmPtr, +) -> __wasi_errno_t { + super::thread_parallelism::(thread, ret_parallelism) +} + +pub(crate) fn thread_exit( + thread: &WasiThread, + exitcode: __wasi_exitcode_t, +) -> Result<__wasi_errno_t, WasiError> { + super::thread_exit(thread, exitcode) +} + +pub(crate) fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { + super::sched_yield(thread) +} + +pub(crate) fn getpid( + thread: &WasiThread, + ret_pid: WasmPtr<__wasi_pid_t, MemoryType>, +) -> __wasi_errno_t { + super::getpid::(thread, ret_pid) +} + +pub(crate) fn bus_spawn_local( + thread: &WasiThread, + name: WasmPtr, + name_len: MemoryOffset, + chroot: __wasi_bool_t, + args: WasmPtr, + args_len: MemoryOffset, + preopen: WasmPtr, + preopen_len: MemoryOffset, + stdin: __wasi_stdiomode_t, + stdout: __wasi_stdiomode_t, + stderr: __wasi_stdiomode_t, + working_dir: WasmPtr, + working_dir_len: MemoryOffset, + ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, +) -> __wasi_errno_t { + super::bus_spawn_local::(thread, name, name_len, chroot, args, args_len, preopen, preopen_len, stdin, stdout, stderr, working_dir, working_dir_len, ret_handles) +} + +pub(crate) fn bus_spawn_remote( + thread: &WasiThread, + name: WasmPtr, + name_len: MemoryOffset, + chroot: __wasi_bool_t, + args: WasmPtr, + args_len: MemoryOffset, + preopen: WasmPtr, + preopen_len: MemoryOffset, + working_dir: WasmPtr, + working_dir_len: MemoryOffset, + stdin: __wasi_stdiomode_t, + stdout: __wasi_stdiomode_t, + stderr: __wasi_stdiomode_t, + instance: WasmPtr, + instance_len: MemoryOffset, + token: WasmPtr, + token_len: MemoryOffset, + ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, +) -> __wasi_errno_t { + super::bus_spawn_remote::(thread, name, name_len, chroot, args, args_len, preopen, preopen_len, working_dir, working_dir_len, stdin, stdout, stderr, instance, instance_len, token, token_len, ret_handles) +} + +pub(crate) fn bus_close( + thread: &WasiThread, + bid: __wasi_bid_t, +) -> __wasi_errno_t { + super::bus_close(thread, bid) +} + +pub(crate) fn bus_invoke( + thread: &WasiThread, + bid: __wasi_bid_t, + cid: WasmPtr<__wasi_option_cid_t, MemoryType>, + keep_alive: __wasi_bool_t, + topic: WasmPtr, + topic_len: MemoryOffset, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: MemoryOffset, + ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, +) -> __wasi_errno_t { + super::bus_invoke::(thread, bid, cid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid) +} + +pub(crate) fn bus_fault( + thread: &WasiThread, + cid: __wasi_cid_t, + fault: __bus_errno_t, +) -> __wasi_errno_t { + super::bus_fault(thread, cid, fault) +} + +pub(crate) fn bus_drop( + thread: &WasiThread, + cid: __wasi_cid_t, +) -> __wasi_errno_t { + super::bus_drop(thread, cid) +} + +pub(crate) fn bus_reply( + thread: &WasiThread, + cid: __wasi_cid_t, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: MemoryOffset, +) -> __wasi_errno_t { + super::bus_reply::(thread, cid, format, buf, buf_len) +} + +pub(crate) fn bus_callback( + thread: &WasiThread, + cid: __wasi_cid_t, + topic: WasmPtr, + topic_len: MemoryOffset, + format: __wasi_busdataformat_t, + buf: WasmPtr, + buf_len: MemoryOffset, +) -> __wasi_errno_t { + super::bus_callback::(thread, cid, topic, topic_len, format, buf, buf_len) +} + +pub(crate) fn bus_listen( + thread: &WasiThread, + parent: WasmPtr<__wasi_option_cid_t, MemoryType>, + topic: WasmPtr, + topic_len: MemoryOffset, +) -> __wasi_errno_t { + super::bus_listen::(thread, parent, topic, topic_len) +} + +pub(crate) fn bus_poll( + thread: &WasiThread, + bid: WasmPtr<__wasi_option_bid_t, MemoryType>, + timeout: WasmPtr<__wasi_timestamp_t, MemoryType>, + events: WasmPtr, + nevents: MemoryOffset, + ret_nevents: WasmPtr, +) -> __wasi_errno_t { + super::bus_poll::(thread, bid, timeout, events, nevents, ret_nevents) +} + +pub(crate) fn bus_poll_data( + thread: &WasiThread, + bid: WasmPtr<__wasi_option_bid_t, MemoryType>, + timeout: WasmPtr<__wasi_timestamp_t, MemoryType>, + topic: WasmPtr, + topic_len: MemoryOffset, + buf: WasmPtr, + buf_len: MemoryOffset, + ret_evt: WasmPtr<__wasi_busevent_data_t, MemoryType>, +) -> __wasi_errno_t { + super::bus_poll_data::(thread, bid, timeout, topic, topic_len, buf, buf_len, ret_evt) +} + +pub(crate) fn port_bridge( + thread: &WasiThread, + network: WasmPtr, + network_len: MemoryOffset, + token: WasmPtr, + token_len: MemoryOffset, + security: __wasi_streamsecurity_t, +) -> __wasi_errno_t { + super::port_bridge::(thread, network, network_len, token, token_len, security) +} + +pub(crate) fn port_unbridge( + thread: &WasiThread, +) -> __wasi_errno_t { + super::port_unbridge(thread) +} + +pub(crate) fn port_dhcp_acquire( + thread: &WasiThread, +) -> __wasi_errno_t { + super::port_dhcp_acquire(thread) +} + +pub(crate) fn port_addr_add( + thread: &WasiThread, + addr: WasmPtr<__wasi_cidr_t, MemoryType>, +) -> __wasi_errno_t { + super::port_addr_add::(thread, addr) +} + +pub(crate) fn port_addr_remove( + thread: &WasiThread, + addr: WasmPtr<__wasi_addr_t, MemoryType>, +) -> __wasi_errno_t { + super::port_addr_remove::(thread, addr) +} + +pub(crate) fn port_addr_clear( + thread: &WasiThread, +) -> __wasi_errno_t { + super::port_addr_clear(thread) +} + +pub(crate) fn port_addr_list( + thread: &WasiThread, + addrs: WasmPtr<__wasi_cidr_t, MemoryType>, + naddrs: WasmPtr, +) -> __wasi_errno_t { + super::port_addr_list::(thread, addrs, naddrs) +} + +pub(crate) fn port_mac( + thread: &WasiThread, + ret_mac: WasmPtr<__wasi_hardwareaddress_t, MemoryType>, +) -> __wasi_errno_t { + super::port_mac::(thread, ret_mac) +} + +pub(crate) fn port_gateway_set( + thread: &WasiThread, + ip: WasmPtr<__wasi_addr_t, MemoryType>, +) -> __wasi_errno_t { + super::port_gateway_set::(thread, ip) +} + +pub(crate) fn port_route_add( + thread: &WasiThread, + cidr: WasmPtr<__wasi_cidr_t, MemoryType>, + via_router: WasmPtr<__wasi_addr_t, MemoryType>, + preferred_until: WasmPtr<__wasi_option_timestamp_t, MemoryType>, + expires_at: WasmPtr<__wasi_option_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::port_route_add::(thread, cidr, via_router, preferred_until, expires_at) +} + +pub(crate) fn port_route_remove( + thread: &WasiThread, + ip: WasmPtr<__wasi_addr_t, MemoryType>, +) -> __wasi_errno_t { + super::port_route_remove::(thread, ip) +} + +pub(crate) fn port_route_clear( + thread: &WasiThread, +) -> __wasi_errno_t { + super::port_route_clear(thread) +} + +pub(crate) fn port_route_list( + thread: &WasiThread, + routes: WasmPtr<__wasi_route_t, MemoryType>, + nroutes: WasmPtr, +) -> __wasi_errno_t { + super::port_route_list::(thread, routes, nroutes) +} + +pub(crate) fn ws_connect( + thread: &WasiThread, + url: WasmPtr, + url_len: MemoryOffset, + ret_sock: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::ws_connect::(thread, url, url_len, ret_sock) +} + +pub(crate) fn http_request( + thread: &WasiThread, + url: WasmPtr, + url_len: MemoryOffset, + method: WasmPtr, + method_len: MemoryOffset, + headers: WasmPtr, + headers_len: MemoryOffset, + gzip: __wasi_bool_t, + ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, +) -> __wasi_errno_t { + super::http_request::(thread, url, url_len, method, method_len, headers, headers_len, gzip, ret_handles) +} + +pub(crate) fn http_status( + thread: &WasiThread, + sock: __wasi_fd_t, + status: WasmPtr<__wasi_http_status_t, MemoryType>, + status_text: WasmPtr, + status_text_len: WasmPtr, + headers: WasmPtr, + headers_len: WasmPtr, +) -> __wasi_errno_t { + super::http_status::(thread, sock, status) +} + +pub(crate) fn sock_status( + thread: &WasiThread, + sock: __wasi_fd_t, + ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType> +) -> __wasi_errno_t { + super::sock_status::(thread, sock, ret_status) +} + +pub(crate) fn sock_addr_local( + thread: &WasiThread, + sock: __wasi_fd_t, + ret_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_addr_local::(thread, sock, ret_addr) +} + +pub(crate) fn sock_addr_peer( + thread: &WasiThread, + sock: __wasi_fd_t, + ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_addr_peer::(thread, sock, ro_addr) +} + +pub(crate) fn sock_open( + thread: &WasiThread, + af: __wasi_addressfamily_t, + ty: __wasi_socktype_t, + pt: __wasi_sockproto_t, + ro_sock: WasmPtr<__wasi_fd_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_open::(thread, af, ty, pt, ro_sock) +} + +pub(crate) fn sock_set_opt_flag( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + flag: __wasi_bool_t, +) -> __wasi_errno_t { + super::sock_set_opt_flag(thread, sock, opt, flag) +} + +pub(crate) fn sock_get_opt_flag( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_flag: WasmPtr<__wasi_bool_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_get_opt_flag::(thread, sock, opt, ret_flag) +} + +pub fn sock_set_opt_time( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_set_opt_time(thread, sock, opt, time) +} + +pub fn sock_get_opt_time( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_get_opt_time(thread, sock, opt, ret_time) +} + +pub fn sock_set_opt_size( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + size: __wasi_filesize_t, +) -> __wasi_errno_t { + super::sock_set_opt_size(thread, sock, opt, size) +} + +pub fn sock_get_opt_size( + thread: &WasiThread, + sock: __wasi_fd_t, + opt: __wasi_sockoption_t, + ret_size: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_get_opt_size(thread, sock, opt, ret_size) +} + +pub(crate) fn sock_join_multicast_v4( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, + iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_join_multicast_v4::(thread, sock, multiaddr, iface) +} + +pub(crate) fn sock_leave_multicast_v4( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, + iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_leave_multicast_v4::(thread, sock, multiaddr, iface) +} + +pub(crate) fn sock_join_multicast_v6( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, + iface: u32, +) -> __wasi_errno_t { + super::sock_join_multicast_v6::(thread, sock, multiaddr, iface) +} + +pub(crate) fn sock_leave_multicast_v6( + thread: &WasiThread, + sock: __wasi_fd_t, + multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, + iface: u32, +) -> __wasi_errno_t { + super::sock_leave_multicast_v6::(thread, sock, multiaddr, iface) +} + +pub(crate) fn sock_bind( + thread: &WasiThread, + sock: __wasi_fd_t, + addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_bind::(thread, sock, addr) +} + +pub(crate) fn sock_listen( + thread: &WasiThread, + sock: __wasi_fd_t, + backlog: MemoryOffset, +) -> __wasi_errno_t { + super::sock_listen::(thread, sock, backlog) +} + +pub(crate) fn sock_accept( + thread: &WasiThread, + sock: __wasi_fd_t, + fd_flags: __wasi_fdflags_t, + ro_fd: WasmPtr<__wasi_fd_t, MemoryType>, + ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_accept::(thread, sock, fd_flags, ro_fd, ro_addr) +} + +pub(crate) fn sock_connect( + thread: &WasiThread, + sock: __wasi_fd_t, + addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> __wasi_errno_t { + super::sock_connect::(thread, sock, addr) +} + +pub(crate) fn sock_recv( + thread: &WasiThread, + sock: __wasi_fd_t, + ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, + ri_data_len: MemoryOffset, + ri_flags: __wasi_riflags_t, + ro_data_len: WasmPtr, + ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_recv::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags) +} + +pub(crate) fn sock_recv_from( + thread: &WasiThread, + sock: __wasi_fd_t, + ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, + ri_data_len: MemoryOffset, + ri_flags: __wasi_riflags_t, + ro_data_len: WasmPtr, + ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, + ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_recv_from::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags, ro_addr) +} + +pub(crate) fn sock_send( + thread: &WasiThread, + sock: __wasi_fd_t, + si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, + si_data_len: MemoryOffset, + si_flags: __wasi_siflags_t, + ret_data_len: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_send::(thread, sock, si_data, si_data_len, si_flags, ret_data_len) +} + +pub(crate) fn sock_send_to( + thread: &WasiThread, + sock: __wasi_fd_t, + si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, + si_data_len: MemoryOffset, + si_flags: __wasi_siflags_t, + addr: WasmPtr<__wasi_addr_port_t, MemoryType>, + ret_data_len: WasmPtr, +) -> Result<__wasi_errno_t, WasiError> { + super::sock_send_to::(thread, sock, si_data, si_data_len, si_flags, addr, ret_data_len) +} + +pub(crate) fn sock_send_file( + thread: &WasiThread, + out_fd: __wasi_fd_t, + in_fd: __wasi_fd_t, + offset: __wasi_filesize_t, + count: __wasi_filesize_t, + ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, +) -> Result<__wasi_errno_t, WasiError> { + unsafe { + super::sock_send_file::(thread, out_fd, in_fd, offset, count, ret_sent) + } +} + +pub(crate) fn sock_shutdown( + thread: &WasiThread, + sock: __wasi_fd_t, + how: __wasi_sdflags_t, +) -> __wasi_errno_t { + super::sock_shutdown(thread, sock, how) +} + +pub(crate) fn resolve( + thread: &WasiThread, + host: WasmPtr, + host_len: MemoryOffset, + port: u16, + ips: WasmPtr<__wasi_addr_t, MemoryType>, + nips: MemoryOffset, + ret_nips: WasmPtr, +) -> __wasi_errno_t { + super::resolve::(thread, host, host_len, port, ips, nips, ret_nips) +} diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index 34a84b4dee7..11d6d81ec0d 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -45,6 +45,12 @@ pub enum WasiVersion { /// `wasi_snapshot_preview1`. Snapshot1, + /// `wasix_32v1`. + Wasix32v1, + + /// `wasix_64v1`. + Wasix64v1, + /// Latest version. /// /// It's a “floating” version, i.e. it's an alias to the latest @@ -64,6 +70,8 @@ impl WasiVersion { match *self { WasiVersion::Snapshot0 => SNAPSHOT0_NAMESPACE, WasiVersion::Snapshot1 => SNAPSHOT1_NAMESPACE, + WasiVersion::Wasix32v1 => WASIX_32V1_NAMESPACE, + WasiVersion::Wasix64v1 => WASIX_64V1_NAMESPACE, WasiVersion::Latest => SNAPSHOT1_NAMESPACE, } } @@ -78,6 +86,8 @@ impl PartialEq for WasiVersion { | (Self::Latest, Self::Latest) | (Self::Snapshot0, Self::Snapshot0) | (Self::Snapshot1, Self::Snapshot1) + | (Self::Wasix32v1, Self::Wasix32v1) + | (Self::Wasix64v1, Self::Wasix64v1) ) } } @@ -94,12 +104,22 @@ impl Ord for WasiVersion { return std::cmp::Ordering::Equal; } match (*self, *other) { - // if snapshot0 is not equal, it must be less - (Self::Snapshot0, _) => std::cmp::Ordering::Less, - (Self::Snapshot1, Self::Snapshot0) | (Self::Latest, Self::Snapshot0) => { + (Self::Snapshot1, Self::Snapshot0) => { + std::cmp::Ordering::Greater + } + (Self::Wasix32v1, Self::Snapshot1) | (Self::Wasix32v1, Self::Snapshot0) => { + std::cmp::Ordering::Greater + } + (Self::Wasix64v1, Self::Wasix32v1) | (Self::Wasix64v1, Self::Snapshot1) | (Self::Wasix64v1, Self::Snapshot0) => { std::cmp::Ordering::Greater } - _ => unreachable!("Missing info about ordering of WasiVerison"), + (Self::Latest, Self::Wasix64v1) | (Self::Latest, Self::Wasix32v1) | (Self::Latest, Self::Snapshot1) | (Self::Latest, Self::Snapshot0) => { + std::cmp::Ordering::Greater + } + // they are not equal and not greater so they must be less + (_, _) => { + std::cmp::Ordering::Less + } } } } @@ -110,6 +130,12 @@ const SNAPSHOT0_NAMESPACE: &str = "wasi_unstable"; /// Namespace for the `Snapshot1` version. const SNAPSHOT1_NAMESPACE: &str = "wasi_snapshot_preview1"; +/// Namespace for the `wasix` version. +const WASIX_32V1_NAMESPACE: &str = "wasix_32v1"; + +/// Namespace for the `wasix` version. +const WASIX_64V1_NAMESPACE: &str = "wasix_64v1"; + /// Detect the version of WASI being used based on the import /// namespaces. /// @@ -126,6 +152,8 @@ pub fn get_wasi_version(module: &Module, strict: bool) -> Option { match first_module.as_str() { SNAPSHOT0_NAMESPACE => Some(WasiVersion::Snapshot0), SNAPSHOT1_NAMESPACE => Some(WasiVersion::Snapshot1), + WASIX_32V1_NAMESPACE => Some(WasiVersion::Wasix32v1), + WASIX_64V1_NAMESPACE => Some(WasiVersion::Wasix64v1), _ => None, } } else { @@ -137,6 +165,8 @@ pub fn get_wasi_version(module: &Module, strict: bool) -> Option { imports.find_map(|module| match module.as_str() { SNAPSHOT0_NAMESPACE => Some(WasiVersion::Snapshot0), SNAPSHOT1_NAMESPACE => Some(WasiVersion::Snapshot1), + WASIX_32V1_NAMESPACE => Some(WasiVersion::Wasix32v1), + WASIX_64V1_NAMESPACE => Some(WasiVersion::Wasix64v1), _ => None, }) } @@ -159,6 +189,12 @@ pub fn get_wasi_versions(module: &Module, strict: bool) -> Option { out.insert(WasiVersion::Snapshot1); } + WASIX_32V1_NAMESPACE => { + out.insert(WasiVersion::Wasix32v1); + } + WASIX_64V1_NAMESPACE => { + out.insert(WasiVersion::Wasix64v1); + } _ => { non_wasi_seen = true; } @@ -178,31 +214,65 @@ mod test { #[test] fn wasi_version_equality() { assert_eq!(WasiVersion::Snapshot0, WasiVersion::Snapshot0); + assert_eq!(WasiVersion::Wasix64v1, WasiVersion::Wasix64v1); + assert_eq!(WasiVersion::Wasix32v1, WasiVersion::Wasix32v1); assert_eq!(WasiVersion::Snapshot1, WasiVersion::Snapshot1); assert_eq!(WasiVersion::Snapshot1, WasiVersion::Latest); assert_eq!(WasiVersion::Latest, WasiVersion::Snapshot1); assert_eq!(WasiVersion::Latest, WasiVersion::Latest); + assert!(WasiVersion::Wasix32v1 != WasiVersion::Wasix64v1); + assert!(WasiVersion::Wasix64v1 != WasiVersion::Wasix32v1); + assert!(WasiVersion::Snapshot1 != WasiVersion::Wasix64v1); + assert!(WasiVersion::Wasix64v1 != WasiVersion::Snapshot1); + assert!(WasiVersion::Snapshot1 != WasiVersion::Wasix32v1); + assert!(WasiVersion::Wasix32v1 != WasiVersion::Snapshot1); assert!(WasiVersion::Snapshot0 != WasiVersion::Snapshot1); assert!(WasiVersion::Snapshot1 != WasiVersion::Snapshot0); assert!(WasiVersion::Snapshot0 != WasiVersion::Latest); assert!(WasiVersion::Latest != WasiVersion::Snapshot0); + assert!(WasiVersion::Snapshot0 != WasiVersion::Latest); + assert!(WasiVersion::Latest != WasiVersion::Snapshot0); + assert!(WasiVersion::Wasix32v1 != WasiVersion::Latest); + assert!(WasiVersion::Wasix64v1 != WasiVersion::Latest); } #[test] fn wasi_version_ordering() { assert!(WasiVersion::Snapshot0 <= WasiVersion::Snapshot0); assert!(WasiVersion::Snapshot1 <= WasiVersion::Snapshot1); + assert!(WasiVersion::Wasix32v1 <= WasiVersion::Wasix32v1); + assert!(WasiVersion::Wasix64v1 <= WasiVersion::Wasix64v1); assert!(WasiVersion::Latest <= WasiVersion::Latest); assert!(WasiVersion::Snapshot0 >= WasiVersion::Snapshot0); assert!(WasiVersion::Snapshot1 >= WasiVersion::Snapshot1); + assert!(WasiVersion::Wasix32v1 >= WasiVersion::Wasix32v1); + assert!(WasiVersion::Wasix64v1 >= WasiVersion::Wasix64v1); assert!(WasiVersion::Latest >= WasiVersion::Latest); - assert!(WasiVersion::Snapshot0 < WasiVersion::Snapshot1); - assert!(WasiVersion::Snapshot1 > WasiVersion::Snapshot0); assert!(WasiVersion::Snapshot0 < WasiVersion::Latest); + assert!(WasiVersion::Snapshot0 < WasiVersion::Wasix32v1); + assert!(WasiVersion::Snapshot0 < WasiVersion::Wasix64v1); + assert!(WasiVersion::Snapshot0 < WasiVersion::Snapshot1); assert!(WasiVersion::Latest > WasiVersion::Snapshot0); + assert!(WasiVersion::Wasix32v1 > WasiVersion::Snapshot0); + assert!(WasiVersion::Wasix64v1 > WasiVersion::Snapshot0); + assert!(WasiVersion::Snapshot1 > WasiVersion::Snapshot0); + + assert!(WasiVersion::Snapshot1 < WasiVersion::Wasix32v1); + assert!(WasiVersion::Snapshot1 < WasiVersion::Wasix64v1); + assert!(WasiVersion::Wasix32v1 > WasiVersion::Snapshot1); + assert!(WasiVersion::Wasix64v1 > WasiVersion::Snapshot1); + + assert!(WasiVersion::Wasix32v1 < WasiVersion::Latest); + assert!(WasiVersion::Wasix32v1 > WasiVersion::Snapshot1); + assert!(WasiVersion::Wasix64v1 < WasiVersion::Latest); + assert!(WasiVersion::Wasix64v1 > WasiVersion::Snapshot1); + assert!(WasiVersion::Latest > WasiVersion::Wasix32v1); + assert!(WasiVersion::Snapshot1 < WasiVersion::Wasix32v1); + assert!(WasiVersion::Latest > WasiVersion::Wasix64v1); + assert!(WasiVersion::Snapshot1 < WasiVersion::Wasix32v1); - assert!(!(WasiVersion::Snapshot1 < WasiVersion::Latest)); - assert!(!(WasiVersion::Latest > WasiVersion::Snapshot1)); + assert!(WasiVersion::Wasix32v1 < WasiVersion::Wasix64v1); + assert!(WasiVersion::Wasix64v1 > WasiVersion::Wasix32v1); } } From 5d7767fdb5760de5d4987ac64a1b481e1b77a185 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 8 Jun 2022 15:06:55 +0200 Subject: [PATCH 3/9] Remove clock feature from chrono crate to remove time dependency --- Cargo.lock | 15 ++------------- lib/wasi/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 01316b7b11a..f36ce7f52f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -323,7 +323,6 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time 0.1.43", "wasm-bindgen", "winapi", ] @@ -2400,16 +2399,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "time" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "time" version = "0.2.27" @@ -3030,7 +3019,7 @@ dependencies = [ "lazy_static", "libc", "log", - "time 0.2.27", + "time", "wasmer", ] @@ -3306,7 +3295,7 @@ version = "2.3.0" dependencies = [ "byteorder", "serde", - "time 0.2.27", + "time", "wasmer-derive", "wasmer-types", ] diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index d05400926b3..2f0d97193fa 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -28,7 +28,7 @@ wasmer-wasi-local-networking = { path = "../wasi-local-networking", version = "= typetag = { version = "0.1", optional = true } serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } bincode = { version = "1.3", optional = true } -chrono = { version = "^0.4", features = [ "wasmbind" ], optional = true } +chrono = { version = "^0.4", default-features = false, features = [ "wasmbind", "std", "clock" ], optional = true } derivative = { version = "^2" } bytes = "1" From 3e9de243a521878115350126b29b251c274c7a1f Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 8 Jun 2022 15:18:50 +0200 Subject: [PATCH 4/9] Fix lint warnings/errors --- examples/wasi_pipes.rs | 4 +- lib/api/src/js/externals/memory.rs | 2 +- lib/api/src/js/mem_access.rs | 6 +- lib/api/src/sys/mem_access.rs | 8 +- lib/cli/src/commands/run/wasi.rs | 9 +- lib/types/src/lib.rs | 4 +- lib/types/src/memory.rs | 54 +- lib/vbus/src/lib.rs | 93 +- lib/vfs/src/host_fs.rs | 6 +- lib/vfs/src/lib.rs | 8 +- lib/vfs/src/mem_fs/file_opener.rs | 6 +- lib/vnet/src/lib.rs | 522 +++----- lib/wasi-local-networking/src/lib.rs | 753 ++++------- lib/wasi-types/src/bus.rs | 4 +- lib/wasi-types/src/lib.rs | 8 +- lib/wasi-types/src/net.rs | 2 +- lib/wasi-types/src/time.rs | 2 +- lib/wasi/src/lib.rs | 41 +- lib/wasi/src/runtime.rs | 50 +- lib/wasi/src/state/builder.rs | 8 +- lib/wasi/src/state/mod.rs | 48 +- lib/wasi/src/state/pipe.rs | 68 +- lib/wasi/src/state/socket.rs | 1391 +++++++++++---------- lib/wasi/src/state/types.rs | 24 +- lib/wasi/src/syscalls/legacy/snapshot0.rs | 8 +- lib/wasi/src/syscalls/mod.rs | 999 +++++++-------- lib/wasi/src/syscalls/wasi.rs | 60 +- lib/wasi/src/syscalls/wasix32.rs | 180 ++- lib/wasi/src/syscalls/wasix64.rs | 180 ++- lib/wasi/src/utils.rs | 25 +- tests/compilers/config.rs | 5 +- tests/lib/wast/src/wasi_wast.rs | 43 +- 32 files changed, 2271 insertions(+), 2350 deletions(-) diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index 588a90317d2..b198843caf1 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -11,11 +11,11 @@ //! //! Ready? +use std::io::{Read, Write}; use wasmer::{Instance, Module, Store}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_universal::Universal; use wasmer_wasi::{Pipe, WasiState}; -use std::io::{Read, Write}; fn main() -> Result<(), Box> { let wasm_path = concat!( @@ -62,7 +62,7 @@ fn main() -> Result<(), Box> { start.call(&[])?; println!("Reading from the WASI stdout..."); - + // To read from the stdout let mut buf = String::new(); output.read_to_string(&mut buf)?; diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index eb9eb7317d1..033ab9cc6d9 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -339,7 +339,7 @@ impl Memory { .len() .try_into() .map_err(|_| MemoryAccessError::Overflow)?; - let view = self.uint8view(); + let view = self.uint8view(); let end = offset.checked_add(len).ok_or(MemoryAccessError::Overflow)?; if end > view.length() { Err(MemoryAccessError::HeapOutOfBounds)?; diff --git a/lib/api/src/js/mem_access.rs b/lib/api/src/js/mem_access.rs index a865b9ac976..9c7cbef967c 100644 --- a/lib/api/src/js/mem_access.rs +++ b/lib/api/src/js/mem_access.rs @@ -88,7 +88,11 @@ impl<'a, T: ValueType> WasmRef<'a, T> { /// Get a `WasmPtr` fror this `WasmRef`. #[inline] pub fn as_ptr(self) -> WasmPtr { - let offset: M::Offset = self.offset.try_into().map_err(|_| "invalid offset into memory").unwrap(); + let offset: M::Offset = self + .offset + .try_into() + .map_err(|_| "invalid offset into memory") + .unwrap(); WasmPtr::::new(offset) } diff --git a/lib/api/src/sys/mem_access.rs b/lib/api/src/sys/mem_access.rs index 74e3849197a..00d7f7144b4 100644 --- a/lib/api/src/sys/mem_access.rs +++ b/lib/api/src/sys/mem_access.rs @@ -1,5 +1,5 @@ use crate::RuntimeError; -use crate::{Memory, Memory32, Memory64, WasmPtr, MemorySize}; +use crate::{Memory, Memory32, Memory64, MemorySize, WasmPtr}; use std::{ convert::TryInto, fmt, @@ -88,7 +88,11 @@ impl<'a, T: ValueType> WasmRef<'a, T> { /// Get a `WasmPtr` fror this `WasmRef`. #[inline] pub fn as_ptr(self) -> WasmPtr { - let offset: M::Offset = self.offset.try_into().map_err(|_| "invalid offset into memory").unwrap(); + let offset: M::Offset = self + .offset + .try_into() + .map_err(|_| "invalid offset into memory") + .unwrap(); WasmPtr::::new(offset) } diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 0c697e5e3fb..bee664457bb 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -41,7 +41,10 @@ pub struct Wasi { /// Enable experimental IO devices #[cfg(feature = "experimental-io-devices")] - #[cfg_attr(feature = "experimental-io-devices", structopt(long = "enable-experimental-io-devices"))] + #[cfg_attr( + feature = "experimental-io-devices", + structopt(long = "enable-experimental-io-devices") + )] enable_experimental_io_devices: bool, /// Allow WASI modules to import multiple versions of WASI without a warning. @@ -93,9 +96,9 @@ impl Wasi { } } - let mut wasi_env = wasi_state_builder.finalize()?; + let wasi_env = wasi_state_builder.finalize()?; let mut wasi_thread = wasi_env.new_thread(); - let import_object = wasi_env.import_object_for_all_wasi_versions(module)?; + let import_object = wasi_thread.import_object_for_all_wasi_versions(module)?; let instance = Instance::new(module, &import_object)?; Ok(instance) } diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index 01ac5c64840..b001ab0a17c 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -83,6 +83,7 @@ pub use crate::indexes::{ pub use crate::initializers::{ DataInitializer, DataInitializerLocation, OwnedDataInitializer, TableInitializer, }; +pub use crate::memory::{Memory32, Memory64, MemorySize}; pub use crate::module::{ExportsIterator, ImportsIterator, ModuleInfo}; pub use crate::native::{NativeWasmType, ValueType}; pub use crate::units::{ @@ -93,9 +94,6 @@ pub use types::{ ExportType, ExternType, FunctionType, GlobalInit, GlobalType, ImportType, MemoryType, Mutability, TableType, Type, V128, }; -pub use crate::memory::{ - MemorySize, Memory32, Memory64 -}; #[cfg(feature = "enable-rkyv")] pub use archives::ArchivableIndexMap; diff --git a/lib/types/src/memory.rs b/lib/types/src/memory.rs index 560dad9bf7d..5dae2b53c42 100644 --- a/lib/types/src/memory.rs +++ b/lib/types/src/memory.rs @@ -52,33 +52,33 @@ impl MemoryStyle { /// This allows code to be generic over 32-bit and 64-bit memories. pub unsafe trait MemorySize: Copy { /// Type used to represent an offset into a memory. This is `u32` or `u64`. - type Offset: Default + - std::fmt::Debug + - std::fmt::Display + - Eq + - Ord + - PartialEq + - PartialOrd + - Clone + - Copy + - ValueType + - Into + - From + - From + - From + - TryFrom + - TryFrom + - TryFrom + - TryFrom + - TryInto + - TryInto + - TryInto + - TryInto + - TryInto + - TryFrom + - Add + - Sum + - AddAssign; + type Offset: Default + + std::fmt::Debug + + std::fmt::Display + + Eq + + Ord + + PartialEq + + PartialOrd + + Clone + + Copy + + ValueType + + Into + + From + + From + + From + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryInto + + TryInto + + TryInto + + TryInto + + TryInto + + TryFrom + + Add + + Sum + + AddAssign; /// Type used to pass this value as an argument or return value for a Wasm function. type Native: super::NativeWasmType; diff --git a/lib/vbus/src/lib.rs b/lib/vbus/src/lib.rs index b949fc84d7c..4f3f23d9b3c 100644 --- a/lib/vbus/src/lib.rs +++ b/lib/vbus/src/lib.rs @@ -3,8 +3,8 @@ use std::pin::Pin; use std::task::{Context, Poll}; use thiserror::Error; -pub use wasmer_vfs::StdioMode; pub use wasmer_vfs::FileDescriptor; +pub use wasmer_vfs::StdioMode; pub type Result = std::result::Result; @@ -16,17 +16,12 @@ pub struct BusDescriptor(usize); #[repr(transparent)] pub struct CallDescriptor(usize); -pub trait VirtualBus: fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualBus: fmt::Debug + Send + Sync + 'static { /// Starts a new WAPM sub process - fn new_spawn( - &self, - ) -> SpawnOptions; + fn new_spawn(&self) -> SpawnOptions; /// Creates a listener thats used to receive BUS commands - fn listen( - &self - )-> Result>; + fn listen(&self) -> Result>; } pub trait VirtualBusSpawner { @@ -159,40 +154,33 @@ impl SpawnOptions { } #[derive(Debug)] -pub struct BusSpawnedProcess -{ +pub struct BusSpawnedProcess { /// Handle of the instance pub handle: BusDescriptor, /// Reference to the spawned instance pub inst: Box, } -pub trait VirtualBusScope: fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualBusScope: fmt::Debug + Send + Sync + 'static { //// Returns true if the invokable target has finished - fn poll_finished( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll<()>; + fn poll_finished(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()>; } -pub trait VirtualBusInvokable: fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualBusInvokable: fmt::Debug + Send + Sync + 'static { /// Invokes a service within this instance fn invoke( &self, topic: String, format: BusDataFormat, - buf: &[u8] + buf: &[u8], ) -> Result>; } -pub trait VirtualBusProcess: VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static +pub trait VirtualBusProcess: + VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static { /// Returns the exit code if the instance has finished - fn exit_code( - &self, - ) -> Option; + fn exit_code(&self) -> Option; /// Returns a file descriptor used to read the STDIN fn stdin_fd(&self) -> Option; @@ -204,18 +192,15 @@ pub trait VirtualBusProcess: VirtualBusScope + VirtualBusInvokable + fmt::Debug fn stderr_fd(&self) -> Option; } -pub trait VirtualBusInvocation: VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static +pub trait VirtualBusInvocation: + VirtualBusScope + VirtualBusInvokable + fmt::Debug + Send + Sync + 'static { /// Polls for new listen events related to this context - fn poll_event( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll; + fn poll_event(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } #[derive(Debug)] -pub enum BusInvocationEvent -{ +pub enum BusInvocationEvent { /// The server has sent some out-of-band data to you Callback { /// Topic that this call relates to @@ -234,18 +219,13 @@ pub enum BusInvocationEvent }, } -pub trait VirtualBusListener: fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualBusListener: fmt::Debug + Send + Sync + 'static { /// Polls for new calls to this service - fn poll_call( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll; + fn poll_call(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } #[derive(Debug)] -pub struct BusCallEvent -{ +pub struct BusCallEvent { /// Topic that this call relates to pub topic: String, /// Reference to the call itself @@ -256,28 +236,15 @@ pub struct BusCallEvent pub data: Vec, } -pub trait VirtualBusCalled: VirtualBusListener + fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualBusCalled: VirtualBusListener + fmt::Debug + Send + Sync + 'static { /// Sends an out-of-band message back to the caller - fn callback( - &self, - topic: String, - format: BusDataFormat, - buf: &[u8], - ) -> Result<()>; + fn callback(&self, topic: String, format: BusDataFormat, buf: &[u8]) -> Result<()>; /// Informs the caller that their call has failed - fn fault( - self, - fault: BusError, - ) -> Result<()>; - - /// Finishes the call and returns a particular response - fn reply( - self, - format: BusDataFormat, - buf: &[u8], - ) -> Result<()>; + fn fault(self, fault: BusError) -> Result<()>; + + /// Finishes the call and returns a particular response + fn reply(self, format: BusDataFormat, buf: &[u8]) -> Result<()>; } /// Format that the supplied data is in @@ -292,10 +259,9 @@ pub enum BusDataFormat { } #[derive(Debug, Default)] -pub struct UnsupportedVirtualBus { } +pub struct UnsupportedVirtualBus {} -impl VirtualBus -for UnsupportedVirtualBus { +impl VirtualBus for UnsupportedVirtualBus { fn new_spawn(&self) -> SpawnOptions { SpawnOptions::new(Box::new(UnsupportedVirtualBusSpawner::default())) } @@ -306,10 +272,9 @@ for UnsupportedVirtualBus { } #[derive(Debug, Default)] -pub struct UnsupportedVirtualBusSpawner { } +pub struct UnsupportedVirtualBusSpawner {} -impl VirtualBusSpawner -for UnsupportedVirtualBusSpawner { +impl VirtualBusSpawner for UnsupportedVirtualBusSpawner { fn spawn(&mut self, _name: &str, _config: &SpawnOptionsConfig) -> Result { Err(BusError::Unsupported) } diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index e058839ed8e..37f715ea288 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -177,7 +177,11 @@ impl TryInto for fs::Metadata { pub struct FileOpener; impl crate::FileOpener for FileOpener { - fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result> { + fn open( + &mut self, + path: &Path, + conf: &OpenOptionsConfig, + ) -> Result> { // TODO: handle create implying write, etc. let read = conf.read(); let write = conf.write(); diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index c74132d6e08..0b8456bfda3 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -51,7 +51,11 @@ impl dyn FileSystem + 'static { } pub trait FileOpener { - fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result>; + fn open( + &mut self, + path: &Path, + conf: &OpenOptionsConfig, + ) -> Result>; } #[derive(Debug, Clone)] @@ -183,7 +187,7 @@ pub trait VirtualFile: fmt::Debug + Send + Write + Read + Seek + 'static + Upcas /// Returns the number of bytes available. This function must not block fn bytes_available(&self) -> Result { return Ok(self.bytes_available_read()?.unwrap_or(0usize) - + self.bytes_available_write()?.unwrap_or(0usize)); + + self.bytes_available_write()?.unwrap_or(0usize)); } /// Returns the number of bytes available. This function must not block diff --git a/lib/vfs/src/mem_fs/file_opener.rs b/lib/vfs/src/mem_fs/file_opener.rs index 6e80dbd1be6..679341badc2 100644 --- a/lib/vfs/src/mem_fs/file_opener.rs +++ b/lib/vfs/src/mem_fs/file_opener.rs @@ -10,7 +10,11 @@ pub struct FileOpener { } impl crate::FileOpener for FileOpener { - fn open(&mut self, path: &Path, conf: &OpenOptionsConfig) -> Result> { + fn open( + &mut self, + path: &Path, + conf: &OpenOptionsConfig, + ) -> Result> { let read = conf.read(); let mut write = conf.write(); let append = conf.append(); diff --git a/lib/vnet/src/lib.rs b/lib/vnet/src/lib.rs index cd33c448a8c..499d709b7d5 100644 --- a/lib/vnet/src/lib.rs +++ b/lib/vnet/src/lib.rs @@ -2,12 +2,12 @@ use std::fmt; use std::net::IpAddr; use std::net::Ipv4Addr; use std::net::Ipv6Addr; -use std::net::SocketAddr; use std::net::Shutdown; +use std::net::SocketAddr; +use std::sync::mpsc; use std::sync::Arc; use std::sync::Mutex; use std::time::Duration; -use std::sync::mpsc; use thiserror::Error; pub use bytes::Bytes; @@ -21,33 +21,27 @@ pub type SocketDescriptor = wasmer_vfs::FileDescriptor; /// Represents an IP address and its netmask #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct IpCidr -{ +pub struct IpCidr { pub ip: IpAddr, pub prefix: u8, } /// Represents a routing entry in the routing table of the interface #[derive(Clone, Debug)] -pub struct IpRoute -{ +pub struct IpRoute { pub cidr: IpCidr, pub via_router: IpAddr, pub preferred_until: Option, - pub expires_at: Option + pub expires_at: Option, } /// An implementation of virtual networking -pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static { /// Establishes a web socket connection /// (note: this does not use the virtual sockets and is standalone /// functionality that works without the network being connected) - fn ws_connect( - &self, - url: &str, - ) -> Result>; - + fn ws_connect(&self, url: &str) -> Result>; + /// Makes a HTTP request to a remote web resource /// The headers are separated by line breaks /// (note: this does not use the virtual sockets and is standalone @@ -59,60 +53,35 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static headers: &str, gzip: bool, ) -> Result; - + /// Bridges this local network with a remote network, which is required in /// order to make lower level networking calls (such as UDP/TCP) - fn bridge( - &self, - network: &str, - access_token: &str, - security: StreamSecurity, - ) -> Result<()>; - + fn bridge(&self, network: &str, access_token: &str, security: StreamSecurity) -> Result<()>; + /// Disconnects from the remote network essentially unbridging it - fn unbridge( - &self, - ) -> Result<()>; - + fn unbridge(&self) -> Result<()>; + /// Acquires an IP address on the network and configures the routing tables - fn dhcp_acquire( - &self, - ) -> Result>; - + fn dhcp_acquire(&self) -> Result>; + /// Adds a static IP address to the interface with a netmask prefix - fn ip_add( - &self, - ip: IpAddr, - prefix: u8, - ) -> Result<()>; - + fn ip_add(&self, ip: IpAddr, prefix: u8) -> Result<()>; + /// Removes a static (or dynamic) IP address from the interface - fn ip_remove( - &self, - ip: IpAddr, - ) -> Result<()>; - + fn ip_remove(&self, ip: IpAddr) -> Result<()>; + /// Clears all the assigned IP addresses for this interface - fn ip_clear( - &self, - ) -> Result<()>; - + fn ip_clear(&self) -> Result<()>; + /// Lists all the IP addresses currently assigned to this interface - fn ip_list( - &self, - ) -> Result>; - + fn ip_list(&self) -> Result>; + /// Returns the hardware MAC address for this interface - fn mac( - &self, - ) -> Result<[u8; 6]>; - + fn mac(&self) -> Result<[u8; 6]>; + /// Adds a default gateway to the routing table - fn gateway_set( - &self, - ip: IpAddr, - ) -> Result<()>; - + fn gateway_set(&self, ip: IpAddr) -> Result<()>; + /// Adds a specific route to the routing table fn route_add( &self, @@ -121,28 +90,19 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static preferred_until: Option, expires_at: Option, ) -> Result<()>; - + /// Removes a routing rule from the routing table - fn route_remove( - &self, - cidr: IpAddr, - ) -> Result<()>; - + fn route_remove(&self, cidr: IpAddr) -> Result<()>; + /// Clears the routing table for this interface - fn route_clear( - &self, - ) -> Result<()>; - + fn route_clear(&self) -> Result<()>; + /// Lists all the routes defined in the routing table for this interface - fn route_list( - &self, - ) -> Result>; - + fn route_list(&self) -> Result>; + /// Creates a low level socket that can read and write Ethernet packets /// directly to the interface - fn bind_raw( - &self, - ) -> Result>; + fn bind_raw(&self) -> Result>; /// Lists for TCP connections on a specific IP and Port combination /// Multiple servers (processes or threads) can bind to the same port if they each set @@ -167,11 +127,8 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static /// Creates a socket that can be used to send and receive ICMP packets /// from a paritcular IP address - fn bind_icmp( - &self, - addr: IpAddr, - ) -> Result>; - + fn bind_icmp(&self, addr: IpAddr) -> Result>; + /// Opens a TCP connection to a particular destination IP address and port fn connect_tcp( &self, @@ -179,7 +136,7 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static peer: SocketAddr, timeout: Option, ) -> Result>; - + /// Performs DNS resolution for a specific hostname fn resolve( &self, @@ -191,8 +148,7 @@ pub trait VirtualNetworking: fmt::Debug + Send + Sync + 'static /// Holds the interface used to work with a pending HTTP request #[derive(Debug)] -pub struct SocketHttpRequest -{ +pub struct SocketHttpRequest { /// Used to send the request bytes to the HTTP server /// (once all bytes are send the sender should be closed) pub request: Option>>, @@ -208,8 +164,7 @@ pub struct SocketHttpRequest /// Represents the final result of a HTTP request #[derive(Debug)] -pub struct HttpStatus -{ +pub struct HttpStatus { /// Indicates if the HTTP request was redirected to another URL / server pub redirected: bool, /// Size of the data held in the response receiver @@ -221,8 +176,7 @@ pub struct HttpStatus } #[derive(Debug)] -pub struct SocketReceive -{ +pub struct SocketReceive { /// Data that was received pub data: Bytes, /// Indicates if the data was truncated (e.g. UDP packet) @@ -230,93 +184,65 @@ pub struct SocketReceive } #[derive(Debug)] -pub struct SocketReceiveFrom -{ +pub struct SocketReceiveFrom { /// Data that was received pub data: Bytes, /// Indicates if the data was truncated (e.g. UDP packet) pub truncated: bool, /// Peer sender address of the data - pub addr: SocketAddr + pub addr: SocketAddr, } -pub trait VirtualTcpListener: fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualTcpListener: fmt::Debug + Send + Sync + 'static { /// Accepts an connection attempt that was made to this listener - fn accept( - &self, - ) -> Result<(Box, SocketAddr)>; + fn accept(&self) -> Result<(Box, SocketAddr)>; /// Accepts an connection attempt that was made to this listener (or times out) fn accept_timeout( &self, - timeout: Duration + timeout: Duration, ) -> Result<(Box, SocketAddr)>; /// Sets the accept timeout - fn set_timeout( - &mut self, - timeout: Option - ) -> Result<()>; + fn set_timeout(&mut self, timeout: Option) -> Result<()>; /// Gets the accept timeout - fn timeout( - &self - ) -> Result>; + fn timeout(&self) -> Result>; /// Returns the local address of this TCP listener - fn addr_local( - &self, - ) -> Result; - + fn addr_local(&self) -> Result; + /// Sets how many network hops the packets are permitted for new connections - fn set_ttl( - &mut self, - ttl: u8, - ) -> Result<()>; - + fn set_ttl(&mut self, ttl: u8) -> Result<()>; + /// Returns the maximum number of network hops before packets are dropped - fn ttl( - &self, - ) -> Result; + fn ttl(&self) -> Result; } -pub trait VirtualSocket: fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualSocket: fmt::Debug + Send + Sync + 'static { /// Sets how many network hops the packets are permitted for new connections - fn set_ttl( - &mut self, - ttl: u32, - ) -> Result<()>; - + fn set_ttl(&mut self, ttl: u32) -> Result<()>; + /// Returns the maximum number of network hops before packets are dropped - fn ttl( - &self, - ) -> Result; + fn ttl(&self) -> Result; /// Returns the local address for this socket - fn addr_local( - &self, - ) -> Result; - + fn addr_local(&self) -> Result; + /// Returns the status/state of the socket - fn status( - &self, - ) -> Result; + fn status(&self) -> Result; } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum SocketStatus -{ +pub enum SocketStatus { Opening, Opened, Closed, - Failed + Failed, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum StreamSecurity -{ +pub enum StreamSecurity { Unencrypted, AnyEncyption, ClassicEncryption, @@ -324,131 +250,86 @@ pub enum StreamSecurity } /// Interface used for sending and receiving data from a web socket -pub trait VirtualWebSocket: fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualWebSocket: fmt::Debug + Send + Sync + 'static { /// Sends out a datagram or stream of bytes on this socket - fn send( - &mut self, - data: Bytes, - ) -> Result; + fn send(&mut self, data: Bytes) -> Result; /// FLushes all the datagrams - fn flush( - &mut self, - ) -> Result<()>; + fn flush(&mut self) -> Result<()>; /// Recv a packet from the socket - fn recv( - &mut self, - ) -> Result; + fn recv(&mut self) -> Result; } /// Connected sockets have a persistent connection to a remote peer -pub trait VirtualConnectedSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualConnectedSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static { /// Determines how long the socket will remain in a TIME_WAIT /// after it disconnects (only the one that initiates the close will /// be in a TIME_WAIT state thus the clients should always do this rather /// than the server) - fn set_linger( - &mut self, - linger: Option, - ) -> Result<()>; + fn set_linger(&mut self, linger: Option) -> Result<()>; /// Returns how long the socket will remain in a TIME_WAIT /// after it disconnects - fn linger( - &self, - ) -> Result>; + fn linger(&self) -> Result>; /// Sends out a datagram or stream of bytes on this socket - fn send( - &mut self, - data: Bytes, - ) -> Result; + fn send(&mut self, data: Bytes) -> Result; /// FLushes all the datagrams - fn flush( - &mut self, - ) -> Result<()>; + fn flush(&mut self) -> Result<()>; /// Recv a packet from the socket - fn recv( - &mut self, - ) -> Result; + fn recv(&mut self) -> Result; /// Peeks for a packet from the socket - fn peek( - &mut self, - ) -> Result; + fn peek(&mut self) -> Result; } /// Connectionless sockets are able to send and receive datagrams and stream /// bytes to multiple addresses at the same time (peer-to-peer) -pub trait VirtualConnectionlessSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualConnectionlessSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static { /// Sends out a datagram or stream of bytes on this socket /// to a specific address - fn send_to( - &mut self, - data: Bytes, - addr: SocketAddr, - ) -> Result; + fn send_to(&mut self, data: Bytes, addr: SocketAddr) -> Result; /// Recv a packet from the socket - fn recv_from( - &mut self, - ) -> Result; + fn recv_from(&mut self) -> Result; /// Peeks for a packet from the socket - fn peek_from( - &mut self, - ) -> Result; + fn peek_from(&mut self) -> Result; } /// ICMP sockets are low level devices bound to a specific address /// that can send and receive ICMP packets -pub trait VirtualIcmpSocket: VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static +pub trait VirtualIcmpSocket: + VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static { } -pub trait VirtualRawSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualRawSocket: VirtualSocket + fmt::Debug + Send + Sync + 'static { /// Sends out a raw packet on this socket - fn send( - &mut self, - data: Bytes, - ) -> Result; + fn send(&mut self, data: Bytes) -> Result; /// FLushes all the datagrams - fn flush( - &mut self, - ) -> Result<()>; + fn flush(&mut self) -> Result<()>; /// Recv a packet from the socket - fn recv( - &mut self, - ) -> Result; + fn recv(&mut self) -> Result; /// Tells the raw socket and its backing switch that all packets /// should be received by this socket even if they are not /// destined for this device - fn set_promiscuous( - &mut self, - promiscuous: bool - ) -> Result<()>; + fn set_promiscuous(&mut self, promiscuous: bool) -> Result<()>; /// Returns if the socket is running in promiscuous mode whereby it /// will receive all packets even if they are not destined for the /// local interface - fn promiscuous( - &self, - ) -> Result; + fn promiscuous(&self) -> Result; } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum TimeType -{ +pub enum TimeType { ReadTimeout, WriteTimeout, AcceptTimeout, @@ -456,254 +337,194 @@ pub enum TimeType Linger, } -pub trait VirtualTcpSocket: VirtualConnectedSocket + fmt::Debug + Send + Sync + 'static -{ +pub trait VirtualTcpSocket: VirtualConnectedSocket + fmt::Debug + Send + Sync + 'static { /// Sets the timeout for a specific action on the socket - fn set_opt_time( - &mut self, - ty: TimeType, - timeout: Option, - ) -> Result<()>; + fn set_opt_time(&mut self, ty: TimeType, timeout: Option) -> Result<()>; /// Returns one of the previous set timeouts - fn opt_time( - &self, - ty: TimeType, - ) -> Result>; + fn opt_time(&self, ty: TimeType) -> Result>; /// Sets the receive buffer size which acts as a trottle for how /// much data is buffered on this side of the pipe - fn set_recv_buf_size( - &mut self, - size: usize, - ) -> Result<()>; - + fn set_recv_buf_size(&mut self, size: usize) -> Result<()>; + /// Size of the receive buffer that holds all data that has not /// yet been read - fn recv_buf_size( - &self, - ) -> Result; - + fn recv_buf_size(&self) -> Result; + /// Sets the size of the send buffer which will hold the bytes of /// data while they are being sent over to the peer - fn set_send_buf_size( - &mut self, - size: usize, - ) -> Result<()>; - + fn set_send_buf_size(&mut self, size: usize) -> Result<()>; + /// Size of the send buffer that holds all data that is currently /// being transmitted. - fn send_buf_size( - &self, - ) -> Result; + fn send_buf_size(&self) -> Result; /// When NO_DELAY is set the data that needs to be transmitted to /// the peer is sent immediately rather than waiting for a bigger /// batch of data, this reduces latency but increases encapsulation /// overhead. - fn set_nodelay( - &mut self, - reuse: bool - ) -> Result<()>; + fn set_nodelay(&mut self, reuse: bool) -> Result<()>; /// Indicates if the NO_DELAY flag is set which means that data /// is immediately sent to the peer without waiting. This reduces /// latency but increases encapsulation overhead. - fn nodelay( - &self, - ) -> Result; + fn nodelay(&self) -> Result; /// Returns the address (IP and Port) of the peer socket that this /// is conencted to - fn addr_peer( - &self, - ) -> Result; + fn addr_peer(&self) -> Result; /// Causes all the data held in the send buffer to be immediately /// flushed to the destination peer - fn flush( - &mut self, - ) -> Result<()>; + fn flush(&mut self) -> Result<()>; /// Shuts down either the READER or WRITER sides of the socket /// connection. - fn shutdown( - &mut self, - how: Shutdown, - ) -> Result<()>; + fn shutdown(&mut self, how: Shutdown) -> Result<()>; } -pub trait VirtualUdpSocket: VirtualConnectedSocket + VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static +pub trait VirtualUdpSocket: + VirtualConnectedSocket + VirtualConnectionlessSocket + fmt::Debug + Send + Sync + 'static { /// Connects to a destination peer so that the normal /// send/recv operations can be used. - fn connect( - &mut self, - addr: SocketAddr, - ) -> Result<()>; + fn connect(&mut self, addr: SocketAddr) -> Result<()>; /// Sets a flag that means that the UDP socket is able /// to receive and process broadcast packets. - fn set_broadcast( - &mut self, - broadcast: bool - ) -> Result<()>; + fn set_broadcast(&mut self, broadcast: bool) -> Result<()>; /// Indicates if the SO_BROADCAST flag is set which means /// that the UDP socket will receive and process broadcast /// packets - fn broadcast( - &self, - ) -> Result; + fn broadcast(&self) -> Result; /// Sets a flag that indicates if multicast packets that /// this socket is a member of will be looped back to /// the sending socket. This applies to IPv4 addresses - fn set_multicast_loop_v4( - &mut self, - val: bool - ) -> Result<()>; + fn set_multicast_loop_v4(&mut self, val: bool) -> Result<()>; /// Gets a flag that indicates if multicast packets that /// this socket is a member of will be looped back to /// the sending socket. This applies to IPv4 addresses - fn multicast_loop_v4( - &self, - ) -> Result; + fn multicast_loop_v4(&self) -> Result; /// Sets a flag that indicates if multicast packets that /// this socket is a member of will be looped back to /// the sending socket. This applies to IPv6 addresses - fn set_multicast_loop_v6( - &mut self, - val: bool - ) -> Result<()>; + fn set_multicast_loop_v6(&mut self, val: bool) -> Result<()>; /// Gets a flag that indicates if multicast packets that /// this socket is a member of will be looped back to /// the sending socket. This applies to IPv6 addresses - fn multicast_loop_v6( - &self, - ) -> Result; - + fn multicast_loop_v6(&self) -> Result; + /// Sets the TTL for IPv4 multicast packets which is the /// number of network hops before the packet is dropped - fn set_multicast_ttl_v4( - &mut self, - ttl: u32, - ) -> Result<()>; - + fn set_multicast_ttl_v4(&mut self, ttl: u32) -> Result<()>; + /// Gets the TTL for IPv4 multicast packets which is the /// number of network hops before the packet is dropped - fn multicast_ttl_v4( - &self, - ) -> Result; - + fn multicast_ttl_v4(&self) -> Result; + /// Tells this interface that it will subscribe to a /// particular multicast address. This applies to IPv4 addresses - fn join_multicast_v4( - &mut self, - multiaddr: Ipv4Addr, - iface: Ipv4Addr, - ) -> Result<()>; - + fn join_multicast_v4(&mut self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<()>; + /// Tells this interface that it will unsubscribe to a /// particular multicast address. This applies to IPv4 addresses - fn leave_multicast_v4( - &mut self, - multiaddr: Ipv4Addr, - iface: Ipv4Addr, - ) -> Result<()>; - + fn leave_multicast_v4(&mut self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<()>; + /// Tells this interface that it will subscribe to a /// particular multicast address. This applies to IPv6 addresses - fn join_multicast_v6( - &mut self, - multiaddr: Ipv6Addr, - iface: u32, - ) -> Result<()>; - + fn join_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<()>; + /// Tells this interface that it will unsubscribe to a /// particular multicast address. This applies to IPv6 addresses - fn leave_multicast_v6( - &mut self, - multiaddr: Ipv6Addr, - iface: u32, - ) -> Result<()>; + fn leave_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<()>; /// Returns the remote address of this UDP socket if it has been /// connected to a specific target destination address - fn addr_peer( - &self, - ) -> Result>; + fn addr_peer(&self) -> Result>; } #[derive(Debug, Default)] -pub struct UnsupportedVirtualNetworking { } +pub struct UnsupportedVirtualNetworking {} -impl VirtualNetworking -for UnsupportedVirtualNetworking -{ +impl VirtualNetworking for UnsupportedVirtualNetworking { fn ws_connect(&self, _url: &str) -> Result> { Err(NetworkError::Unsupported) } - - fn http_request(&self, _url: &str, _method: &str, _headers: &str, _gzip: bool) -> Result { + + fn http_request( + &self, + _url: &str, + _method: &str, + _headers: &str, + _gzip: bool, + ) -> Result { Err(NetworkError::Unsupported) } - + fn bridge(&self, _network: &str, _access_token: &str, _security: StreamSecurity) -> Result<()> { Err(NetworkError::Unsupported) } - + fn unbridge(&self) -> Result<()> { Err(NetworkError::Unsupported) } - + fn dhcp_acquire(&self) -> Result> { Err(NetworkError::Unsupported) } - + fn ip_add(&self, _ip: IpAddr, _prefix: u8) -> Result<()> { Err(NetworkError::Unsupported) } - + fn ip_remove(&self, _ip: IpAddr) -> Result<()> { Err(NetworkError::Unsupported) } - + fn ip_clear(&self) -> Result<()> { Err(NetworkError::Unsupported) } - + fn ip_list(&self) -> Result> { Err(NetworkError::Unsupported) } - + fn mac(&self) -> Result<[u8; 6]> { Err(NetworkError::Unsupported) } - + fn gateway_set(&self, _ip: IpAddr) -> Result<()> { Err(NetworkError::Unsupported) } - - fn route_add(&self, _cidr: IpCidr, _via_router: IpAddr, _preferred_until: Option, _expires_at: Option) -> Result<()> { + + fn route_add( + &self, + _cidr: IpCidr, + _via_router: IpAddr, + _preferred_until: Option, + _expires_at: Option, + ) -> Result<()> { Err(NetworkError::Unsupported) } - + fn route_remove(&self, _cidr: IpAddr) -> Result<()> { Err(NetworkError::Unsupported) } - + fn route_clear(&self) -> Result<()> { Err(NetworkError::Unsupported) } - + fn route_list(&self) -> Result> { Err(NetworkError::Unsupported) } - + fn bind_raw(&self) -> Result> { Err(NetworkError::Unsupported) } @@ -712,19 +533,40 @@ for UnsupportedVirtualNetworking Err(NetworkError::Unsupported) } - fn listen_tcp(&self, _addr: SocketAddr, _only_v6: bool, _reuse_port: bool, _reuse_addr: bool) -> Result> { + fn listen_tcp( + &self, + _addr: SocketAddr, + _only_v6: bool, + _reuse_port: bool, + _reuse_addr: bool, + ) -> Result> { Err(NetworkError::Unsupported) } - - fn connect_tcp(&self, _addr: SocketAddr, _peer: SocketAddr, _timeout: Option) -> Result> { + + fn connect_tcp( + &self, + _addr: SocketAddr, + _peer: SocketAddr, + _timeout: Option, + ) -> Result> { Err(NetworkError::Unsupported) } - fn bind_udp(&self, _addr: SocketAddr, _reuse_port: bool, _reuse_addr: bool) -> Result> { + fn bind_udp( + &self, + _addr: SocketAddr, + _reuse_port: bool, + _reuse_addr: bool, + ) -> Result> { Err(NetworkError::Unsupported) } - - fn resolve(&self, _host: &str, _port: Option, _dns_server: Option) -> Result> { + + fn resolve( + &self, + _host: &str, + _port: Option, + _dns_server: Option, + ) -> Result> { Err(NetworkError::Unsupported) } } diff --git a/lib/wasi-local-networking/src/lib.rs b/lib/wasi-local-networking/src/lib.rs index 968902c0b12..b6dc6924e7b 100644 --- a/lib/wasi-local-networking/src/lib.rs +++ b/lib/wasi-local-networking/src/lib.rs @@ -1,55 +1,26 @@ #![allow(unused_variables)] -use std::time::Duration; -use std::net::{ - IpAddr, - SocketAddr, - Shutdown, Ipv6Addr, Ipv4Addr, -}; -use std::io::{ - Read, - Write, -}; use bytes::{Bytes, BytesMut}; -use wasmer_vnet::{ - io_err_into_net_error, - VirtualConnectedSocket, - VirtualSocket, - VirtualNetworking, - VirtualWebSocket, - VirtualTcpListener, - VirtualRawSocket, - VirtualUdpSocket, - VirtualIcmpSocket, - VirtualTcpSocket, - SocketHttpRequest, - StreamSecurity, - SocketReceive, - SocketStatus, - IpCidr, - IpRoute, - TimeType, - Result, - NetworkError, VirtualConnectionlessSocket, SocketReceiveFrom -}; +use std::io::{Read, Write}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use std::time::Duration; #[allow(unused_imports, dead_code)] use tracing::{debug, error, info, trace, warn}; +use wasmer_vnet::{ + io_err_into_net_error, IpCidr, IpRoute, NetworkError, Result, SocketHttpRequest, SocketReceive, + SocketReceiveFrom, SocketStatus, StreamSecurity, TimeType, VirtualConnectedSocket, + VirtualConnectionlessSocket, VirtualIcmpSocket, VirtualNetworking, VirtualRawSocket, + VirtualSocket, VirtualTcpListener, VirtualTcpSocket, VirtualUdpSocket, VirtualWebSocket, +}; #[derive(Debug, Default)] -pub struct LocalNetworking -{ -} +pub struct LocalNetworking {} #[allow(unused_variables)] -impl VirtualNetworking -for LocalNetworking -{ - fn ws_connect( - &self, - url: &str, - ) -> Result> { +impl VirtualNetworking for LocalNetworking { + fn ws_connect(&self, url: &str) -> Result> { Err(NetworkError::Unsupported) } - + fn http_request( &self, url: &str, @@ -59,68 +30,43 @@ for LocalNetworking ) -> Result { Err(NetworkError::Unsupported) } - - fn bridge( - &self, - network: &str, - access_token: &str, - security: StreamSecurity, - ) -> Result<()> { + + fn bridge(&self, network: &str, access_token: &str, security: StreamSecurity) -> Result<()> { Err(NetworkError::Unsupported) } - - fn unbridge( - &self, - ) -> Result<()> { + + fn unbridge(&self) -> Result<()> { Err(NetworkError::Unsupported) } - - fn dhcp_acquire( - &self, - ) -> Result> { + + fn dhcp_acquire(&self) -> Result> { Err(NetworkError::Unsupported) } - - fn ip_add( - &self, - ip: IpAddr, - prefix: u8, - ) -> Result<()> { + + fn ip_add(&self, ip: IpAddr, prefix: u8) -> Result<()> { Err(NetworkError::Unsupported) } - - fn ip_remove( - &self, - ip: IpAddr, - ) -> Result<()> { + + fn ip_remove(&self, ip: IpAddr) -> Result<()> { Err(NetworkError::Unsupported) } - - fn ip_clear( - &self, - ) -> Result<()> { + + fn ip_clear(&self) -> Result<()> { Err(NetworkError::Unsupported) } - - fn ip_list( - &self, - ) -> Result> { + + fn ip_list(&self) -> Result> { Err(NetworkError::Unsupported) } - - fn mac( - &self, - ) -> Result<[u8; 6]> { + + fn mac(&self) -> Result<[u8; 6]> { Err(NetworkError::Unsupported) } - - fn gateway_set( - &self, - ip: IpAddr, - ) -> Result<()> { + + fn gateway_set(&self, ip: IpAddr) -> Result<()> { Err(NetworkError::Unsupported) } - + fn route_add( &self, cidr: IpCidr, @@ -130,29 +76,20 @@ for LocalNetworking ) -> Result<()> { Err(NetworkError::Unsupported) } - - fn route_remove( - &self, - cidr: IpAddr, - ) -> Result<()> { + + fn route_remove(&self, cidr: IpAddr) -> Result<()> { Err(NetworkError::Unsupported) } - - fn route_clear( - &self, - ) -> Result<()> { + + fn route_clear(&self) -> Result<()> { Err(NetworkError::Unsupported) } - - fn route_list( - &self, - ) -> Result> { + + fn route_list(&self) -> Result> { Err(NetworkError::Unsupported) } - - fn bind_raw( - &self, - ) -> Result> { + + fn bind_raw(&self) -> Result> { Err(NetworkError::Unsupported) } @@ -164,10 +101,12 @@ for LocalNetworking reuse_addr: bool, ) -> Result> { let listener = std::net::TcpListener::bind(addr) - .map(|sock| Box::new(LocalTcpListener { - stream: sock, - timeout: None, - })) + .map(|sock| { + Box::new(LocalTcpListener { + stream: sock, + timeout: None, + }) + }) .map_err(io_err_into_net_error)?; Ok(listener) } @@ -178,18 +117,14 @@ for LocalNetworking _reuse_port: bool, _reuse_addr: bool, ) -> Result> { - let socket = std::net::UdpSocket::bind(addr) - .map_err(io_err_into_net_error)?; + let socket = std::net::UdpSocket::bind(addr).map_err(io_err_into_net_error)?; Ok(Box::new(LocalUdpSocket(socket, addr))) } - fn bind_icmp( - &self, - addr: IpAddr, - ) -> Result> { + fn bind_icmp(&self, addr: IpAddr) -> Result> { Err(NetworkError::Unsupported) } - + fn connect_tcp( &self, _addr: SocketAddr, @@ -197,20 +132,19 @@ for LocalNetworking timeout: Option, ) -> Result> { let stream = if let Some(timeout) = timeout { - std::net::TcpStream::connect_timeout(&peer, timeout) - } else { - std::net::TcpStream::connect(peer) - } - .map_err(io_err_into_net_error)?; - let peer = stream.peer_addr() - .map_err(io_err_into_net_error)?; + std::net::TcpStream::connect_timeout(&peer, timeout) + } else { + std::net::TcpStream::connect(peer) + } + .map_err(io_err_into_net_error)?; + let peer = stream.peer_addr().map_err(io_err_into_net_error)?; Ok(Box::new(LocalTcpStream { stream, addr: peer, connect_timeout: None, })) } - + fn resolve( &self, host: &str, @@ -218,22 +152,16 @@ for LocalNetworking dns_server: Option, ) -> Result> { use std::net::ToSocketAddrs; - Ok( - if let Some(port) = port { - let host = format!("{}:{}", host, port); - host.to_socket_addrs() - .map(|a| a - .map(|a| a.ip()) - .collect::>()) - .map_err(io_err_into_net_error)? - } else { - host.to_socket_addrs() - .map(|a| a - .map(|a| a.ip()) - .collect::>()) - .map_err(io_err_into_net_error)? - } - ) + Ok(if let Some(port) = port { + let host = format!("{}:{}", host, port); + host.to_socket_addrs() + .map(|a| a.map(|a| a.ip()).collect::>()) + .map_err(io_err_into_net_error)? + } else { + host.to_socket_addrs() + .map(|a| a.map(|a| a.ip()).collect::>()) + .map_err(io_err_into_net_error)? + }) } } @@ -243,27 +171,26 @@ pub struct LocalTcpListener { timeout: Option, } -impl VirtualTcpListener -for LocalTcpListener -{ - fn accept( - &self, - ) -> Result<(Box, SocketAddr)> { +impl VirtualTcpListener for LocalTcpListener { + fn accept(&self) -> Result<(Box, SocketAddr)> { if let Some(timeout) = &self.timeout { - return self.accept_timeout(timeout.clone()) + return self.accept_timeout(timeout.clone()); } - let (sock, addr) = self.stream.accept() + let (sock, addr) = self + .stream + .accept() .map(|(sock, addr)| { - (Box::new(LocalTcpStream { - stream: sock, - addr: addr.clone(), - connect_timeout: None, - }), addr) + ( + Box::new(LocalTcpStream { + stream: sock, + addr: addr.clone(), + connect_timeout: None, + }), + addr, + ) }) .map_err(io_err_into_net_error)?; - Ok( - (sock, addr) - ) + Ok((sock, addr)) } #[cfg(feature = "wasix")] @@ -271,18 +198,21 @@ for LocalTcpListener &self, timeout: Duration, ) -> Result<(Box, SocketAddr)> { - let (sock, addr) = self.stream.accept_timeout(timeout) + let (sock, addr) = self + .stream + .accept_timeout(timeout) .map(|(sock, addr)| { - (Box::new(LocalTcpStream { - stream: sock, - addr: addr.clone(), - connect_timeout: None, - }), addr) + ( + Box::new(LocalTcpStream { + stream: sock, + addr: addr.clone(), + connect_timeout: None, + }), + addr, + ) }) .map_err(io_err_into_net_error)?; - Ok( - (sock, addr) - ) + Ok((sock, addr)) } #[cfg(not(feature = "wasix"))] @@ -294,41 +224,27 @@ for LocalTcpListener } /// Sets the accept timeout - fn set_timeout( - &mut self, - timeout: Option - ) -> Result<()> { + fn set_timeout(&mut self, timeout: Option) -> Result<()> { self.timeout = timeout; Ok(()) } /// Gets the accept timeout - fn timeout( - &self - ) -> Result> { + fn timeout(&self) -> Result> { Ok(self.timeout.clone()) } - fn addr_local( - &self, - ) -> Result { - self.stream - .local_addr() - .map_err(io_err_into_net_error) + fn addr_local(&self) -> Result { + self.stream.local_addr().map_err(io_err_into_net_error) } - - fn set_ttl( - &mut self, - ttl: u8, - ) -> Result<()> { + + fn set_ttl(&mut self, ttl: u8) -> Result<()> { self.stream .set_ttl(ttl as u32) .map_err(io_err_into_net_error) } - - fn ttl( - &self, - ) -> Result { + + fn ttl(&self) -> Result { self.stream .ttl() .map(|ttl| ttl as u8) @@ -343,31 +259,31 @@ pub struct LocalTcpStream { connect_timeout: Option, } -impl VirtualTcpSocket -for LocalTcpStream -{ - fn set_opt_time( - &mut self, - ty: TimeType, - timeout: Option, - ) -> Result<()> { +impl VirtualTcpSocket for LocalTcpStream { + fn set_opt_time(&mut self, ty: TimeType, timeout: Option) -> Result<()> { match ty { - TimeType::ReadTimeout => self.stream.set_read_timeout(timeout).map_err(io_err_into_net_error), - TimeType::WriteTimeout => self.stream.set_write_timeout(timeout).map_err(io_err_into_net_error), + TimeType::ReadTimeout => self + .stream + .set_read_timeout(timeout) + .map_err(io_err_into_net_error), + TimeType::WriteTimeout => self + .stream + .set_write_timeout(timeout) + .map_err(io_err_into_net_error), TimeType::ConnectTimeout => { self.connect_timeout = timeout; Ok(()) - }, + } #[cfg(feature = "wasix")] - TimeType::Linger => self.stream.set_linger(timeout).map_err(io_err_into_net_error), + TimeType::Linger => self + .stream + .set_linger(timeout) + .map_err(io_err_into_net_error), _ => Err(NetworkError::InvalidInput), } } - fn opt_time( - &self, - ty: TimeType, - ) -> Result> { + fn opt_time(&self, ty: TimeType) -> Result> { match ty { TimeType::ReadTimeout => self.stream.read_timeout().map_err(io_err_into_net_error), TimeType::WriteTimeout => self.stream.write_timeout().map_err(io_err_into_net_error), @@ -378,433 +294,294 @@ for LocalTcpStream } } - fn set_recv_buf_size( - &mut self, - size: usize, - ) -> Result<()> { + fn set_recv_buf_size(&mut self, size: usize) -> Result<()> { Ok(()) } - - fn recv_buf_size( - &self, - ) -> Result { + + fn recv_buf_size(&self) -> Result { Err(NetworkError::Unsupported) } - - fn set_send_buf_size( - &mut self, - size: usize, - ) -> Result<()> { + + fn set_send_buf_size(&mut self, size: usize) -> Result<()> { Ok(()) } - - fn send_buf_size( - &self, - ) -> Result { + + fn send_buf_size(&self) -> Result { Err(NetworkError::Unsupported) } - fn set_nodelay( - &mut self, - nodelay: bool - ) -> Result<()> { - self.stream.set_nodelay(nodelay).map_err(io_err_into_net_error) + fn set_nodelay(&mut self, nodelay: bool) -> Result<()> { + self.stream + .set_nodelay(nodelay) + .map_err(io_err_into_net_error) } - fn nodelay( - &self, - ) -> Result { + fn nodelay(&self) -> Result { self.stream.nodelay().map_err(io_err_into_net_error) } - fn addr_peer( - &self, - ) -> Result { + fn addr_peer(&self) -> Result { Ok(self.addr.clone()) } - fn flush( - &mut self, - ) -> Result<()> { + fn flush(&mut self) -> Result<()> { Ok(()) } - fn shutdown( - &mut self, - how: Shutdown, - ) -> Result<()> { + fn shutdown(&mut self, how: Shutdown) -> Result<()> { self.stream.shutdown(how).map_err(io_err_into_net_error) } } -impl VirtualConnectedSocket -for LocalTcpStream -{ - fn set_linger( - &mut self, - linger: Option, - ) -> Result<()> { +impl VirtualConnectedSocket for LocalTcpStream { + fn set_linger(&mut self, linger: Option) -> Result<()> { #[cfg(feature = "wasix")] - self.stream.set_linger(linger).map_err(io_err_into_net_error)?; + self.stream + .set_linger(linger) + .map_err(io_err_into_net_error)?; Ok(()) } #[cfg(feature = "wasix")] - fn linger( - &self, - ) -> Result> { + fn linger(&self) -> Result> { self.stream.linger().map_err(io_err_into_net_error) } #[cfg(not(feature = "wasix"))] - fn linger( - &self, - ) -> Result> { + fn linger(&self) -> Result> { Ok(None) } - - fn send( - &mut self, - data: Bytes, - ) -> Result { - self.stream.write_all(&data[..]) + + fn send(&mut self, data: Bytes) -> Result { + self.stream + .write_all(&data[..]) .map(|_| data.len()) .map_err(io_err_into_net_error) } - - fn flush( - &mut self, - ) -> Result<()> { - self.stream.flush() - .map_err(io_err_into_net_error) + + fn flush(&mut self) -> Result<()> { + self.stream.flush().map_err(io_err_into_net_error) } - - fn recv( - &mut self, - ) -> Result { + + fn recv(&mut self) -> Result { let buf_size = 8192; let mut buf = BytesMut::with_capacity(buf_size); - let read = self.stream.read(&mut buf[..]) + let read = self + .stream + .read(&mut buf[..]) .map_err(io_err_into_net_error)?; let buf = Bytes::from(buf).slice(..read); - Ok( - SocketReceive { - data: buf, - truncated: read == buf_size - } - ) + Ok(SocketReceive { + data: buf, + truncated: read == buf_size, + }) } - - fn peek( - &mut self, - ) -> Result { + + fn peek(&mut self) -> Result { let buf_size = 8192; let mut buf = BytesMut::with_capacity(buf_size); - let read = self.stream.peek(&mut buf[..]) + let read = self + .stream + .peek(&mut buf[..]) .map_err(io_err_into_net_error)?; let buf = Bytes::from(buf).slice(..read); - Ok( - SocketReceive { - data: buf, - truncated: read == buf_size - } - ) + Ok(SocketReceive { + data: buf, + truncated: read == buf_size, + }) } } -impl VirtualSocket -for LocalTcpStream -{ - fn set_ttl( - &mut self, - ttl: u32, - ) -> Result<()> { - self.stream.set_ttl(ttl) - .map_err(io_err_into_net_error) +impl VirtualSocket for LocalTcpStream { + fn set_ttl(&mut self, ttl: u32) -> Result<()> { + self.stream.set_ttl(ttl).map_err(io_err_into_net_error) } - fn ttl( - &self, - ) -> Result { - self.stream.ttl() - .map_err(io_err_into_net_error) + fn ttl(&self) -> Result { + self.stream.ttl().map_err(io_err_into_net_error) } - fn addr_local( - &self, - ) -> Result { - self.stream.local_addr() - .map_err(io_err_into_net_error) + fn addr_local(&self) -> Result { + self.stream.local_addr().map_err(io_err_into_net_error) } - - fn status( - &self, - ) -> Result { - Ok( - SocketStatus::Opened - ) + + fn status(&self) -> Result { + Ok(SocketStatus::Opened) } } #[derive(Debug)] pub struct LocalUdpSocket(std::net::UdpSocket, SocketAddr); -impl VirtualUdpSocket -for LocalUdpSocket -{ - fn connect( - &mut self, - addr: SocketAddr, - ) -> Result<()> { - self.0.connect(addr) - .map_err(io_err_into_net_error) +impl VirtualUdpSocket for LocalUdpSocket { + fn connect(&mut self, addr: SocketAddr) -> Result<()> { + self.0.connect(addr).map_err(io_err_into_net_error) } - fn set_broadcast( - &mut self, - broadcast: bool - ) -> Result<()> { - self.0.set_broadcast(broadcast) + fn set_broadcast(&mut self, broadcast: bool) -> Result<()> { + self.0 + .set_broadcast(broadcast) .map_err(io_err_into_net_error) } - fn broadcast( - &self, - ) -> Result { - self.0.broadcast() - .map_err(io_err_into_net_error) + fn broadcast(&self) -> Result { + self.0.broadcast().map_err(io_err_into_net_error) } - fn set_multicast_loop_v4( - &mut self, - val: bool - ) -> Result<()> { - self.0.set_multicast_loop_v4(val) + fn set_multicast_loop_v4(&mut self, val: bool) -> Result<()> { + self.0 + .set_multicast_loop_v4(val) .map_err(io_err_into_net_error) } - fn multicast_loop_v4( - &self, - ) -> Result { - self.0.multicast_loop_v4() - .map_err(io_err_into_net_error) + fn multicast_loop_v4(&self) -> Result { + self.0.multicast_loop_v4().map_err(io_err_into_net_error) } - fn set_multicast_loop_v6( - &mut self, - val: bool - ) -> Result<()> { - self.0.set_multicast_loop_v6(val) + fn set_multicast_loop_v6(&mut self, val: bool) -> Result<()> { + self.0 + .set_multicast_loop_v6(val) .map_err(io_err_into_net_error) } - fn multicast_loop_v6( - &self, - ) -> Result { - self.0.multicast_loop_v6() - .map_err(io_err_into_net_error) + fn multicast_loop_v6(&self) -> Result { + self.0.multicast_loop_v6().map_err(io_err_into_net_error) } - fn set_multicast_ttl_v4( - &mut self, - ttl: u32, - ) -> Result<()> { - self.0.set_multicast_ttl_v4(ttl) + fn set_multicast_ttl_v4(&mut self, ttl: u32) -> Result<()> { + self.0 + .set_multicast_ttl_v4(ttl) .map_err(io_err_into_net_error) } - fn multicast_ttl_v4( - &self, - ) -> Result { - self.0.multicast_ttl_v4() - .map_err(io_err_into_net_error) + fn multicast_ttl_v4(&self) -> Result { + self.0.multicast_ttl_v4().map_err(io_err_into_net_error) } - fn join_multicast_v4( - &mut self, - multiaddr: Ipv4Addr, - iface: Ipv4Addr, - ) -> Result<()> { - self.0.join_multicast_v4(&multiaddr, &iface) + fn join_multicast_v4(&mut self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<()> { + self.0 + .join_multicast_v4(&multiaddr, &iface) .map_err(io_err_into_net_error) } - fn leave_multicast_v4( - &mut self, - multiaddr: Ipv4Addr, - iface: Ipv4Addr, - ) -> Result<()> { - self.0.leave_multicast_v4(&multiaddr, &iface) + fn leave_multicast_v4(&mut self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<()> { + self.0 + .leave_multicast_v4(&multiaddr, &iface) .map_err(io_err_into_net_error) } - fn join_multicast_v6( - &mut self, - multiaddr: Ipv6Addr, - iface: u32, - ) -> Result<()> { - self.0.join_multicast_v6(&multiaddr, iface) + fn join_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<()> { + self.0 + .join_multicast_v6(&multiaddr, iface) .map_err(io_err_into_net_error) } - fn leave_multicast_v6( - &mut self, - multiaddr: Ipv6Addr, - iface: u32, - ) -> Result<()> { - self.0.leave_multicast_v6(&multiaddr, iface) + fn leave_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<()> { + self.0 + .leave_multicast_v6(&multiaddr, iface) .map_err(io_err_into_net_error) } - fn addr_peer( - &self, - ) -> Result> { - self.0.peer_addr() + fn addr_peer(&self) -> Result> { + self.0 + .peer_addr() .map(|a| Some(a)) .map_err(io_err_into_net_error) } } -impl VirtualConnectedSocket -for LocalUdpSocket -{ - fn set_linger( - &mut self, - linger: Option, - ) -> Result<()> { +impl VirtualConnectedSocket for LocalUdpSocket { + fn set_linger(&mut self, linger: Option) -> Result<()> { Err(NetworkError::Unsupported) } - fn linger( - &self, - ) -> Result> { + fn linger(&self) -> Result> { Err(NetworkError::Unsupported) } - fn send( - &mut self, - data: Bytes, - ) -> Result { - self.0.send(&data[..]) - .map_err(io_err_into_net_error) + fn send(&mut self, data: Bytes) -> Result { + self.0.send(&data[..]).map_err(io_err_into_net_error) } - - fn flush( - &mut self, - ) -> Result<()> { + + fn flush(&mut self) -> Result<()> { Ok(()) } - - fn recv( - &mut self, - ) -> Result { + + fn recv(&mut self) -> Result { let buf_size = 8192; let mut buf = BytesMut::with_capacity(buf_size); - let read = self.0.recv(&mut buf[..]) - .map_err(io_err_into_net_error)?; + let read = self.0.recv(&mut buf[..]).map_err(io_err_into_net_error)?; let buf = Bytes::from(buf).slice(..read); - Ok( - SocketReceive { - data: buf, - truncated: read == buf_size - } - ) + Ok(SocketReceive { + data: buf, + truncated: read == buf_size, + }) } - - fn peek( - &mut self, - ) -> Result { + + fn peek(&mut self) -> Result { let buf_size = 8192; let mut buf = BytesMut::with_capacity(buf_size); - let read = self.0.peek(&mut buf[..]) - .map_err(io_err_into_net_error)?; + let read = self.0.peek(&mut buf[..]).map_err(io_err_into_net_error)?; let buf = Bytes::from(buf).slice(..read); - Ok( - SocketReceive { - data: buf, - truncated: read == buf_size - } - ) + Ok(SocketReceive { + data: buf, + truncated: read == buf_size, + }) } } -impl VirtualConnectionlessSocket -for LocalUdpSocket -{ - fn send_to( - &mut self, - data: Bytes, - addr: SocketAddr, - ) -> Result { - self.0.send_to(&data[..], addr) +impl VirtualConnectionlessSocket for LocalUdpSocket { + fn send_to(&mut self, data: Bytes, addr: SocketAddr) -> Result { + self.0 + .send_to(&data[..], addr) .map_err(io_err_into_net_error) } - fn recv_from( - &mut self, - ) -> Result { + fn recv_from(&mut self) -> Result { let buf_size = 8192; let mut buf = BytesMut::with_capacity(buf_size); - let (read, peer) = self.0.recv_from(&mut buf[..]) + let (read, peer) = self + .0 + .recv_from(&mut buf[..]) .map_err(io_err_into_net_error)?; let buf = Bytes::from(buf).slice(..read); - Ok( - SocketReceiveFrom { - data: buf, - truncated: read == buf_size, - addr: peer - } - ) + Ok(SocketReceiveFrom { + data: buf, + truncated: read == buf_size, + addr: peer, + }) } - fn peek_from( - &mut self, - ) -> Result { + fn peek_from(&mut self) -> Result { let buf_size = 8192; let mut buf = BytesMut::with_capacity(buf_size); - let (read, peer) = self.0.peek_from(&mut buf[..]) + let (read, peer) = self + .0 + .peek_from(&mut buf[..]) .map_err(io_err_into_net_error)?; let buf = Bytes::from(buf).slice(..read); - Ok( - SocketReceiveFrom { - data: buf, - truncated: read == buf_size, - addr: peer - } - ) + Ok(SocketReceiveFrom { + data: buf, + truncated: read == buf_size, + addr: peer, + }) } } -impl VirtualSocket -for LocalUdpSocket -{ - fn set_ttl( - &mut self, - ttl: u32, - ) -> Result<()> { - self.0.set_ttl(ttl) - .map_err(io_err_into_net_error) +impl VirtualSocket for LocalUdpSocket { + fn set_ttl(&mut self, ttl: u32) -> Result<()> { + self.0.set_ttl(ttl).map_err(io_err_into_net_error) } - fn ttl( - &self, - ) -> Result { - self.0.ttl() - .map_err(io_err_into_net_error) + fn ttl(&self) -> Result { + self.0.ttl().map_err(io_err_into_net_error) } - fn addr_local( - &self, - ) -> Result { - self.0.local_addr() - .map_err(io_err_into_net_error) + fn addr_local(&self) -> Result { + self.0.local_addr().map_err(io_err_into_net_error) } - - fn status( - &self, - ) -> Result { - Ok( - SocketStatus::Opened - ) + + fn status(&self) -> Result { + Ok(SocketStatus::Opened) } } diff --git a/lib/wasi-types/src/bus.rs b/lib/wasi-types/src/bus.rs index afc1073cc8a..bdbd7bcfa6d 100644 --- a/lib/wasi-types/src/bus.rs +++ b/lib/wasi-types/src/bus.rs @@ -1,6 +1,6 @@ +use super::*; use wasmer_derive::ValueType; use wasmer_types::MemorySize; -use super::*; pub type __wasi_busdatatype_t = u8; pub const __WASI_BUS_DATA_TYPE_CALL: __wasi_busdatatype_t = 0; @@ -50,7 +50,7 @@ pub struct __wasi_bus_handles_t { #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] pub struct __wasi_busevent_exit_t { - pub rval: __wasi_exitcode_t + pub rval: __wasi_exitcode_t, } #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] diff --git a/lib/wasi-types/src/lib.rs b/lib/wasi-types/src/lib.rs index 0eb568aa026..14f9bff188b 100644 --- a/lib/wasi-types/src/lib.rs +++ b/lib/wasi-types/src/lib.rs @@ -12,13 +12,13 @@ extern crate wasmer_types as wasmer; mod advice; +mod bus; mod directory; mod error; mod event; mod file; -mod bus; -mod net; mod io; +mod net; mod signal; mod subscription; mod time; @@ -26,13 +26,13 @@ mod versions; pub use crate::time::*; pub use advice::*; +pub use bus::*; pub use directory::*; pub use error::*; pub use event::*; pub use file::*; -pub use bus::*; -pub use net::*; pub use io::*; +pub use net::*; pub use signal::*; pub use subscription::*; pub use versions::*; diff --git a/lib/wasi-types/src/net.rs b/lib/wasi-types/src/net.rs index eb45892c759..7f0cbd79f64 100644 --- a/lib/wasi-types/src/net.rs +++ b/lib/wasi-types/src/net.rs @@ -1,5 +1,5 @@ -use wasmer_derive::ValueType; use super::*; +use wasmer_derive::ValueType; use crate::__wasi_option_timestamp_t; diff --git a/lib/wasi-types/src/time.rs b/lib/wasi-types/src/time.rs index f39514835cd..de9a2b26b92 100644 --- a/lib/wasi-types/src/time.rs +++ b/lib/wasi-types/src/time.rs @@ -1,5 +1,5 @@ -use wasmer_derive::ValueType; use super::io::__wasi_option_t; +use wasmer_derive::ValueType; pub type __wasi_clockid_t = u32; pub const __WASI_CLOCK_REALTIME: __wasi_clockid_t = 0; diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index b390eda62d7..5ff475d8b1d 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -35,39 +35,41 @@ compile_error!( #[macro_use] mod macros; +mod runtime; mod state; mod syscalls; mod utils; -mod runtime; use crate::syscalls::*; pub use crate::state::{ - Fd, Pipe, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder, WasiStateCreationError, - ALL_RIGHTS, VIRTUAL_ROOT_FD, + Fd, Pipe, Stderr, Stdin, Stdout, WasiFs, WasiInodes, WasiState, WasiStateBuilder, + WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, }; pub use crate::syscalls::types; pub use crate::utils::{get_wasi_version, get_wasi_versions, is_wasi_module, WasiVersion}; +pub use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus}; #[deprecated(since = "2.1.0", note = "Please use `wasmer_vfs::FsError`")] pub use wasmer_vfs::FsError as WasiFsError; #[deprecated(since = "2.1.0", note = "Please use `wasmer_vfs::VirtualFile`")] pub use wasmer_vfs::VirtualFile as WasiFile; pub use wasmer_vfs::{FsError, VirtualFile}; -pub use wasmer_vbus::{VirtualBus, UnsupportedVirtualBus}; -pub use wasmer_vnet::{VirtualNetworking, UnsupportedVirtualNetworking}; +pub use wasmer_vnet::{UnsupportedVirtualNetworking, VirtualNetworking}; use wasmer_wasi_types::__WASI_CLOCK_MONOTONIC; use derivative::*; use std::ops::Deref; use thiserror::Error; use wasmer::{ - imports, Function, Imports, LazyInit, Memory, MemoryAccessError, Module, Store, WasmerEnv, - MemorySize, Memory32, + imports, Function, Imports, LazyInit, Memory, Memory32, MemoryAccessError, MemorySize, Module, + Store, WasmerEnv, }; -use std::time::Duration; +pub use runtime::{ + PlugableRuntimeImplementation, WasiRuntimeImplementation, WasiThreadError, WasiTtyState, +}; use std::sync::{Arc, RwLockReadGuard, RwLockWriteGuard}; -pub use runtime::{WasiRuntimeImplementation, PlugableRuntimeImplementation, WasiThreadError, WasiTtyState}; +use std::time::Duration; /// This is returned in `RuntimeError`. /// Use `downcast` or `downcast_ref` to retrieve the `ExitCode`. @@ -84,10 +86,14 @@ pub enum WasiError { pub struct WasiThreadId(u32); impl From for WasiThreadId { - fn from(id: u32) -> Self { Self(id) } + fn from(id: u32) -> Self { + Self(id) + } } impl Into for WasiThreadId { - fn into(self) -> u32 { self.0 } + fn into(self) -> u32 { + self.0 + } } /// WASI processes can have multiple threads attached to the same environment @@ -131,14 +137,18 @@ impl WasiThread { let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; let delta = match now.checked_sub(start) { Some(a) => a, - None => { break; } - }; + None => { + break; + } + }; if delta >= duration { break; } let remaining = match duration.checked_sub(delta) { Some(a) => Duration::from_nanos(a as u64), - None => { break; } + None => { + break; + } }; std::thread::sleep(remaining.min(Duration::from_millis(10))); self.yield_now()?; @@ -254,7 +264,8 @@ impl WasiEnv { /// Overrides the runtime implementation for this environment pub fn set_runtime(&mut self, runtime: R) - where R: WasiRuntimeImplementation + Send + Sync + 'static + where + R: WasiRuntimeImplementation + Send + Sync + 'static, { self.runtime = Arc::new(runtime); } diff --git a/lib/wasi/src/runtime.rs b/lib/wasi/src/runtime.rs index a8306a2cd61..ae196747e9d 100644 --- a/lib/wasi/src/runtime.rs +++ b/lib/wasi/src/runtime.rs @@ -1,13 +1,13 @@ +use std::fmt; use std::ops::Deref; use std::sync::atomic::{AtomicU32, Ordering}; -use std::fmt; use thiserror::Error; -use wasmer_vbus::{VirtualBus, UnsupportedVirtualBus}; -use wasmer_vnet::{VirtualNetworking}; +use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus}; +use wasmer_vnet::VirtualNetworking; +use super::types::*; use super::WasiError; use super::WasiThreadId; -use super::types::*; #[derive(Error, Debug)] pub enum WasiThreadError { @@ -17,13 +17,11 @@ pub enum WasiThreadError { MethodNotFound, } -impl Into<__wasi_errno_t> -for WasiThreadError -{ +impl Into<__wasi_errno_t> for WasiThreadError { fn into(self) -> __wasi_errno_t { match self { WasiThreadError::Unsupported => __WASI_ENOTSUP, - WasiThreadError::MethodNotFound => __WASI_EINVAL + WasiThreadError::MethodNotFound => __WASI_EINVAL, } } } @@ -43,8 +41,7 @@ pub struct WasiTtyState { /// Represents an implementation of the WASI runtime - by default everything is /// unimplemented. -pub trait WasiRuntimeImplementation: fmt::Debug + Sync -{ +pub trait WasiRuntimeImplementation: fmt::Debug + Sync { /// For WASI runtimes that support it they can implement a message BUS implementation /// which allows runtimes to pass serialized messages between each other similar to /// RPC's. BUS implementation can be implemented that communicate across runtimes @@ -74,11 +71,15 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync } /// Sets the TTY state - fn tty_set(&self, _tty_state: WasiTtyState) { - } - - /// Spawns a new thread by invoking the - fn thread_spawn(&self, _method: &str, _user_data: u64, _reactor: bool) -> Result { + fn tty_set(&self, _tty_state: WasiTtyState) {} + + /// Spawns a new thread by invoking the + fn thread_spawn( + &self, + _method: &str, + _user_data: u64, + _reactor: bool, + ) -> Result { Err(WasiThreadError::Unsupported) } @@ -107,31 +108,29 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync } #[derive(Debug)] -pub struct PlugableRuntimeImplementation -{ +pub struct PlugableRuntimeImplementation { pub bus: Box, pub networking: Box, pub thread_id_seed: AtomicU32, } -impl PlugableRuntimeImplementation -{ +impl PlugableRuntimeImplementation { pub fn set_bus_implementation(&mut self, bus: I) - where I: VirtualBus + Sync + where + I: VirtualBus + Sync, { self.bus = Box::new(bus) } pub fn set_networking_implementation(&mut self, net: I) - where I: VirtualNetworking + Sync + where + I: VirtualNetworking + Sync, { self.networking = Box::new(net) } } -impl Default -for PlugableRuntimeImplementation -{ +impl Default for PlugableRuntimeImplementation { fn default() -> Self { Self { #[cfg(not(feature = "host-vnet"))] @@ -144,8 +143,7 @@ for PlugableRuntimeImplementation } } -impl WasiRuntimeImplementation -for PlugableRuntimeImplementation { +impl WasiRuntimeImplementation for PlugableRuntimeImplementation { fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { self.bus.deref() } diff --git a/lib/wasi/src/state/builder.rs b/lib/wasi/src/state/builder.rs index bd0607bdcb4..3760b6f67ec 100644 --- a/lib/wasi/src/state/builder.rs +++ b/lib/wasi/src/state/builder.rs @@ -4,10 +4,10 @@ use crate::state::{default_fs_backing, WasiFs, WasiState}; use crate::syscalls::types::{__WASI_STDERR_FILENO, __WASI_STDIN_FILENO, __WASI_STDOUT_FILENO}; use crate::{WasiEnv, WasiInodes}; use generational_arena::Arena; -use std::sync::Arc; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; +use std::sync::Arc; use std::sync::RwLock; use thiserror::Error; use wasmer_vfs::{FsError, VirtualFile}; @@ -329,7 +329,8 @@ impl WasiStateBuilder { /// Sets the WASI runtime implementation and overrides the default /// implementation pub fn runtime(&mut self, runtime: R) -> &mut Self - where R: crate::WasiRuntimeImplementation + Send + Sync + 'static + where + R: crate::WasiRuntimeImplementation + Send + Sync + 'static, { self.runtime_override = Some(Arc::new(runtime)); self @@ -456,7 +457,8 @@ impl WasiStateBuilder { } if let Some(f) = &self.setup_fs_fn { - f(inodes.deref_mut(), &mut wasi_fs).map_err(WasiStateCreationError::WasiFsSetupError)?; + f(inodes.deref_mut(), &mut wasi_fs) + .map_err(WasiStateCreationError::WasiFsSetupError)?; } wasi_fs }; diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 97da17af7f4..273b76662e0 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -16,14 +16,14 @@ #![allow(clippy::cognitive_complexity, clippy::too_many_arguments)] mod builder; -mod types; -mod socket; mod pipe; +mod socket; +mod types; pub use self::builder::*; -pub use self::types::*; -pub use self::socket::*; pub use self::pipe::*; +pub use self::socket::*; +pub use self::types::*; use crate::syscalls::types::*; use crate::utils::map_io_err; use generational_arena::Arena; @@ -32,17 +32,16 @@ pub use generational_arena::Index as Inode; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::collections::VecDeque; -use std::sync::Arc; use std::sync::mpsc; +use std::sync::Arc; use std::{ borrow::Borrow, io::Write, ops::{Deref, DerefMut}, path::{Path, PathBuf}, sync::{ - Mutex, atomic::{AtomicU32, AtomicU64, Ordering}, - RwLock, RwLockReadGuard, RwLockWriteGuard, + Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, }, }; use tracing::{debug, trace}; @@ -191,12 +190,11 @@ pub enum Kind { EventNotifications { /// Used for event notifications by the user application or operating system counter: Arc, - /// Flag that indicates if this is operating + /// Flag that indicates if this is operating is_semaphore: bool, /// Receiver that wakes sleeping threads wakers: Arc>>>, }, - } #[derive(Debug, Clone)] @@ -856,10 +854,7 @@ impl WasiFs { } /// Changes the current directory - pub fn set_current_dir( - &self, - path: &str - ) { + pub fn set_current_dir(&self, path: &str) { let mut guard = self.current_dir.lock().unwrap(); *guard = path.to_string(); } @@ -881,7 +876,13 @@ impl WasiFs { let guard = self.current_dir.lock().unwrap(); guard.clone() }; - let inode = self.get_inode_at_path_inner(inodes, VIRTUAL_ROOT_FD, current_dir.as_str(), symlink_count, true)?; + let inode = self.get_inode_at_path_inner( + inodes, + VIRTUAL_ROOT_FD, + current_dir.as_str(), + symlink_count, + true, + )?; Ok((inode, current_dir)) } @@ -919,7 +920,8 @@ impl WasiFs { // path to the inode before we do the search if path.components().next().map(|c| c.as_os_str().to_str()).flatten() == Some(".") && base == VIRTUAL_ROOT_FD // File queries will occur on the root first - && symlink_count == 0 // The resolving of the current path only should happen once and not after symbolic links are followed + && symlink_count == 0 + // The resolving of the current path only should happen once and not after symbolic links are followed { (cur_inode, _) = self.get_current_dir_inner(inodes, symlink_count + 1)?; } @@ -949,9 +951,7 @@ impl WasiFs { return Err(__WASI_EACCES); } } - "." => { - continue 'path_iter - }, + "." => continue 'path_iter, _ => (), } // used for full resolution of symlinks @@ -1111,7 +1111,10 @@ impl WasiFs { return Err(__WASI_ENOENT); } } - Kind::File { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { + Kind::File { .. } + | Kind::Socket { .. } + | Kind::Pipe { .. } + | Kind::EventNotifications { .. } => { return Err(__WASI_ENOTDIR); } Kind::Symlink { @@ -1512,10 +1515,7 @@ impl WasiFs { Ok(idx) } - pub fn clone_fd( - &self, - fd: __wasi_fd_t, - ) -> Result<__wasi_fd_t, __wasi_errno_t> { + pub fn clone_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_fd_t, __wasi_errno_t> { let fd = self.get_fd(fd)?; let idx = self.next_fd.fetch_add(1, Ordering::AcqRel); self.fd_map.write().unwrap().insert( @@ -1766,7 +1766,7 @@ impl WasiFs { return Err(__WASI_EINVAL); } } - Kind::EventNotifications { .. } => { } + Kind::EventNotifications { .. } => {} Kind::Root { .. } => return Err(__WASI_EACCES), Kind::Symlink { .. } | Kind::Buffer { .. } => return Err(__WASI_EINVAL), } diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index 696ad9899d5..b46133e7f09 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -1,17 +1,16 @@ -use std::sync::mpsc; -use std::sync::Mutex; -use std::ops::DerefMut; +use crate::syscalls::types::*; +use crate::syscalls::{read_bytes, write_bytes}; +use bytes::{Buf, Bytes}; use std::convert::TryInto; use std::io::{self, Read}; -use bytes::{Buf, Bytes}; +use std::ops::DerefMut; +use std::sync::mpsc; +use std::sync::Mutex; use wasmer::MemorySize; -use crate::syscalls::types::*; use wasmer::{Memory, WasmSlice}; -use crate::syscalls::{read_bytes, write_bytes}; #[derive(Debug)] -pub struct WasiPipe -{ +pub struct WasiPipe { /// Sends bytes down the pipe tx: Mutex>>, /// Receives bytes from the pipe @@ -20,55 +19,62 @@ pub struct WasiPipe read_buffer: Option, } -impl WasiPipe -{ - pub fn new() -> (WasiPipe, WasiPipe) - { +impl WasiPipe { + pub fn new() -> (WasiPipe, WasiPipe) { let (tx1, rx1) = mpsc::channel(); let (tx2, rx2) = mpsc::channel(); - + let pipe1 = WasiPipe { tx: Mutex::new(tx1), rx: Mutex::new(rx2), - read_buffer: None + read_buffer: None, }; let pipe2 = WasiPipe { tx: Mutex::new(tx2), rx: Mutex::new(rx1), - read_buffer: None + read_buffer: None, }; (pipe1, pipe2) } - pub fn recv(&mut self, memory: &Memory, iov: WasmSlice<__wasi_iovec_t>) -> Result { + pub fn recv( + &mut self, + memory: &Memory, + iov: WasmSlice<__wasi_iovec_t>, + ) -> Result { loop { if let Some(buf) = self.read_buffer.as_mut() { let buf_len = buf.len(); if buf_len > 0 { let reader = buf.as_ref(); - let read = read_bytes(reader, memory, iov) - .map(|_| buf_len as usize)?; + let read = read_bytes(reader, memory, iov).map(|_| buf_len as usize)?; buf.advance(read); return Ok(read); } } let rx = self.rx.lock().unwrap(); - let data = rx.recv() - .map_err(|_| __WASI_EIO)?; + let data = rx.recv().map_err(|_| __WASI_EIO)?; self.read_buffer.replace(Bytes::from(data)); } } - pub fn send(&mut self, memory: &Memory, iov: WasmSlice<__wasi_ciovec_t>) -> Result { - let buf_len: M::Offset = iov.iter().filter_map(|a| a.read().ok()).map(|a| a.buf_len).sum(); + pub fn send( + &mut self, + memory: &Memory, + iov: WasmSlice<__wasi_ciovec_t>, + ) -> Result { + let buf_len: M::Offset = iov + .iter() + .filter_map(|a| a.read().ok()) + .map(|a| a.buf_len) + .sum(); let buf_len: usize = buf_len.try_into().map_err(|_| __WASI_EINVAL)?; let mut buf = Vec::with_capacity(buf_len); write_bytes(&mut buf, memory, iov)?; let tx = self.tx.lock().unwrap(); - tx.send(buf) - .map_err(|_| __WASI_EIO)?; + tx.send(buf).map_err(|_| __WASI_EIO)?; Ok(buf_len) } @@ -87,27 +93,25 @@ impl WasiPipe } } -impl Read -for WasiPipe -{ +impl Read for WasiPipe { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { loop { if let Some(inner_buf) = self.read_buffer.as_mut() { let buf_len = inner_buf.len(); if buf_len > 0 { let mut reader = inner_buf.as_ref(); - let read = reader.read(buf) - .map(|_| buf_len as usize)?; + let read = reader.read(buf).map(|_| buf_len as usize)?; inner_buf.advance(read); return Ok(read); } } let rx = self.rx.lock().unwrap(); - let data = rx.recv() - .map_err(|_| io::Error::new( + let data = rx.recv().map_err(|_| { + io::Error::new( io::ErrorKind::BrokenPipe, format!("the wasi pipe is not connected"), - ))?; + ) + })?; self.read_buffer.replace(Bytes::from(data)); } } diff --git a/lib/wasi/src/state/socket.rs b/lib/wasi/src/state/socket.rs index 625f51215ad..bd44a2c2a2b 100644 --- a/lib/wasi/src/state/socket.rs +++ b/lib/wasi/src/state/socket.rs @@ -1,34 +1,21 @@ -use std::sync::Mutex; -use std::time::Duration; -use std::mem::transmute; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use super::types::net_error_into_wasi_err; +use crate::syscalls::types::*; +use crate::syscalls::{read_bytes, write_bytes}; +use bytes::{Buf, Bytes}; use std::convert::TryInto; use std::io::{self, Read}; -use bytes::{Buf, Bytes}; -use wasmer_vnet::{ - TimeType, - net_error_into_io_err -}; -use crate::syscalls::types::*; -use wasmer::{Memory, WasmSlice, WasmPtr, MemorySize}; +use std::mem::transmute; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::sync::Mutex; +use std::time::Duration; +#[allow(unused_imports)] +use tracing::{debug, error, info, warn}; +use wasmer::{Memory, MemorySize, WasmPtr, WasmSlice}; +use wasmer_vnet::{net_error_into_io_err, TimeType}; use wasmer_vnet::{ - IpCidr, - IpRoute, - SocketHttpRequest, - VirtualNetworking, - VirtualWebSocket, - VirtualIcmpSocket, - VirtualRawSocket, - VirtualTcpListener, - VirtualTcpSocket, - VirtualUdpSocket, -}; -use super::types::{ - net_error_into_wasi_err, + IpCidr, IpRoute, SocketHttpRequest, VirtualIcmpSocket, VirtualNetworking, VirtualRawSocket, + VirtualTcpListener, VirtualTcpSocket, VirtualUdpSocket, VirtualWebSocket, }; -use crate::syscalls::{read_bytes, write_bytes}; -#[allow(unused_imports)] -use tracing::{debug, error, warn, info}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; @@ -46,8 +33,7 @@ pub enum InodeHttpSocketType { #[derive(Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub enum InodeSocketKind -{ +pub enum InodeSocketKind { PreSocket { family: __wasi_addressfamily_t, ty: __wasi_socktype_t, @@ -73,8 +59,7 @@ pub enum InodeSocketKind Closed, } -pub enum WasiSocketOption -{ +pub enum WasiSocketOption { Noop, ReusePort, ReuseAddr, @@ -104,9 +89,7 @@ pub enum WasiSocketOption Proto, } -impl From<__wasi_sockoption_t> -for WasiSocketOption -{ +impl From<__wasi_sockoption_t> for WasiSocketOption { fn from(opt: __wasi_sockoption_t) -> Self { use WasiSocketOption::*; match opt { @@ -137,14 +120,13 @@ for WasiSocketOption __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => MulticastTtlV4, __WASI_SOCK_OPTION_TYPE => Type, __WASI_SOCK_OPTION_PROTO => Proto, - _ => return Noop + _ => return Noop, } } } #[derive(Debug)] -pub enum WasiSocketStatus -{ +pub enum WasiSocketStatus { Opening, Opened, Closed, @@ -161,38 +143,46 @@ pub struct WasiHttpStatus { #[derive(Debug)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] -pub struct InodeSocket -{ +pub struct InodeSocket { kind: InodeSocketKind, read_buffer: Option, read_addr: Option, } -impl InodeSocket -{ +impl InodeSocket { pub fn new(kind: InodeSocketKind) -> InodeSocket { InodeSocket { kind, read_buffer: None, - read_addr: None + read_addr: None, } } - pub fn bind(&mut self, net: &(dyn VirtualNetworking), set_addr: SocketAddr) -> Result, __wasi_errno_t> { + pub fn bind( + &mut self, + net: &(dyn VirtualNetworking), + set_addr: SocketAddr, + ) -> Result, __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::PreSocket { family, ty, addr, reuse_port, reuse_addr, .. } => - { + InodeSocketKind::PreSocket { + family, + ty, + addr, + reuse_port, + reuse_addr, + .. + } => { match *family { __WASI_ADDRESS_FAMILY_INET4 => { if set_addr.is_ipv4() == false { return Err(__WASI_EINVAL); } - }, + } __WASI_ADDRESS_FAMILY_INET6 => { if set_addr.is_ipv6() == false { return Err(__WASI_EINVAL); } - }, + } _ => { return Err(__WASI_ENOTSUP); } @@ -200,277 +190,286 @@ impl InodeSocket addr.replace(set_addr); let addr = addr.clone().unwrap(); - - Ok( - match *ty { - __WASI_SOCK_TYPE_STREAM => { - // we already set the socket address - next we need a bind or connect so nothing - // more to do at this time - None - }, - __WASI_SOCK_TYPE_DGRAM => { - let socket = net - .bind_udp(addr, *reuse_port, *reuse_addr) - .map_err(net_error_into_wasi_err)?; - Some( - InodeSocket::new(InodeSocketKind::UdpSocket(socket)) - ) - }, - _ => return Err(__WASI_EINVAL) + + Ok(match *ty { + __WASI_SOCK_TYPE_STREAM => { + // we already set the socket address - next we need a bind or connect so nothing + // more to do at this time + None } - ) - }, + __WASI_SOCK_TYPE_DGRAM => { + let socket = net + .bind_udp(addr, *reuse_port, *reuse_addr) + .map_err(net_error_into_wasi_err)?; + Some(InodeSocket::new(InodeSocketKind::UdpSocket(socket))) + } + _ => return Err(__WASI_EINVAL), + }) + } _ => Err(__WASI_ENOTSUP), } } - pub fn listen(&mut self, net: &(dyn VirtualNetworking), _backlog: usize) -> Result, __wasi_errno_t> { + pub fn listen( + &mut self, + net: &(dyn VirtualNetworking), + _backlog: usize, + ) -> Result, __wasi_errno_t> { match &self.kind { - InodeSocketKind::PreSocket { ty, addr, only_v6, reuse_port, reuse_addr, accept_timeout, .. } => { - Ok( - match *ty { - __WASI_SOCK_TYPE_STREAM => { - if addr.is_none() { return Err(__WASI_EINVAL); } - let addr = addr.as_ref().unwrap().clone(); - let mut socket = net - .listen_tcp(addr, *only_v6, *reuse_port, *reuse_addr) - .map_err(net_error_into_wasi_err)?; - if let Some(accept_timeout) = accept_timeout { - socket.set_timeout(Some(accept_timeout.clone())) - .map_err(net_error_into_wasi_err)?; - } - Some( - InodeSocket::new(InodeSocketKind::TcpListener(socket)) - ) - }, - _ => return Err(__WASI_ENOTSUP) + InodeSocketKind::PreSocket { + ty, + addr, + only_v6, + reuse_port, + reuse_addr, + accept_timeout, + .. + } => Ok(match *ty { + __WASI_SOCK_TYPE_STREAM => { + if addr.is_none() { + return Err(__WASI_EINVAL); } - ) - } + let addr = addr.as_ref().unwrap().clone(); + let mut socket = net + .listen_tcp(addr, *only_v6, *reuse_port, *reuse_addr) + .map_err(net_error_into_wasi_err)?; + if let Some(accept_timeout) = accept_timeout { + socket + .set_timeout(Some(accept_timeout.clone())) + .map_err(net_error_into_wasi_err)?; + } + Some(InodeSocket::new(InodeSocketKind::TcpListener(socket))) + } + _ => return Err(__WASI_ENOTSUP), + }), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - pub fn accept(&self, _fd_flags: __wasi_fdflags_t) -> Result<(Box, SocketAddr), __wasi_errno_t> { + pub fn accept( + &self, + _fd_flags: __wasi_fdflags_t, + ) -> Result<(Box, SocketAddr), __wasi_errno_t> { let (sock, addr) = match &self.kind { - InodeSocketKind::TcpListener(sock) => { - sock.accept().map_err(net_error_into_wasi_err) - }, + InodeSocketKind::TcpListener(sock) => sock.accept().map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), }?; - Ok( - (sock, addr) - ) + Ok((sock, addr)) } - pub fn accept_timeout(&self, _fd_flags: __wasi_fdflags_t, timeout: Duration) -> Result<(Box, SocketAddr), __wasi_errno_t> { + pub fn accept_timeout( + &self, + _fd_flags: __wasi_fdflags_t, + timeout: Duration, + ) -> Result<(Box, SocketAddr), __wasi_errno_t> { let (sock, addr) = match &self.kind { - InodeSocketKind::TcpListener(sock) => { - sock.accept_timeout(timeout).map_err(net_error_into_wasi_err) - }, + InodeSocketKind::TcpListener(sock) => sock + .accept_timeout(timeout) + .map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), }?; - Ok( - (sock, addr) - ) + Ok((sock, addr)) } - pub fn connect(&mut self, net: &(dyn VirtualNetworking), peer: SocketAddr) -> Result, __wasi_errno_t> { + pub fn connect( + &mut self, + net: &(dyn VirtualNetworking), + peer: SocketAddr, + ) -> Result, __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::PreSocket { ty, addr, send_timeout, recv_timeout, connect_timeout, .. } => { - Ok( - match *ty { - __WASI_SOCK_TYPE_STREAM => { - let addr = match addr { - Some(a) => a.clone(), - None => { - let ip = match peer.is_ipv4() { - true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), - false => IpAddr::V6(Ipv6Addr::UNSPECIFIED) - }; - SocketAddr::new(ip, 0) - } + InodeSocketKind::PreSocket { + ty, + addr, + send_timeout, + recv_timeout, + connect_timeout, + .. + } => Ok(match *ty { + __WASI_SOCK_TYPE_STREAM => { + let addr = match addr { + Some(a) => a.clone(), + None => { + let ip = match peer.is_ipv4() { + true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + false => IpAddr::V6(Ipv6Addr::UNSPECIFIED), }; - let mut socket = net - .connect_tcp(addr, peer, connect_timeout.clone()) - .map_err(net_error_into_wasi_err)?; - if let Some(timeout) = send_timeout { - socket.set_opt_time(TimeType::WriteTimeout, Some(timeout.clone())) - .map_err(net_error_into_wasi_err)?; - } - if let Some(timeout) = recv_timeout { - socket.set_opt_time(TimeType::ReadTimeout, Some(timeout.clone())) - .map_err(net_error_into_wasi_err)?; - } - Some( - InodeSocket::new(InodeSocketKind::TcpStream(socket)) - ) - }, - __WASI_SOCK_TYPE_DGRAM => return Err(__WASI_EINVAL), - _ => return Err(__WASI_ENOTSUP) + SocketAddr::new(ip, 0) + } + }; + let mut socket = net + .connect_tcp(addr, peer, connect_timeout.clone()) + .map_err(net_error_into_wasi_err)?; + if let Some(timeout) = send_timeout { + socket + .set_opt_time(TimeType::WriteTimeout, Some(timeout.clone())) + .map_err(net_error_into_wasi_err)?; } - ) - } + if let Some(timeout) = recv_timeout { + socket + .set_opt_time(TimeType::ReadTimeout, Some(timeout.clone())) + .map_err(net_error_into_wasi_err)?; + } + Some(InodeSocket::new(InodeSocketKind::TcpStream(socket))) + } + __WASI_SOCK_TYPE_DGRAM => return Err(__WASI_EINVAL), + _ => return Err(__WASI_ENOTSUP), + }), InodeSocketKind::UdpSocket(sock) => { sock.connect(peer).map_err(net_error_into_wasi_err)?; Ok(None) - }, + } InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } pub fn status(&self) -> Result { - Ok( - match &self.kind { - InodeSocketKind::PreSocket { .. } => WasiSocketStatus::Opening, - InodeSocketKind::WebSocket(_) => WasiSocketStatus::Opened, - InodeSocketKind::HttpRequest( .. ) => WasiSocketStatus::Opened, - InodeSocketKind::TcpListener(_) => WasiSocketStatus::Opened, - InodeSocketKind::TcpStream(_) => WasiSocketStatus::Opened, - InodeSocketKind::UdpSocket(_) => WasiSocketStatus::Opened, - InodeSocketKind::Closed => WasiSocketStatus::Closed, - _ => WasiSocketStatus::Failed, - } - ) + Ok(match &self.kind { + InodeSocketKind::PreSocket { .. } => WasiSocketStatus::Opening, + InodeSocketKind::WebSocket(_) => WasiSocketStatus::Opened, + InodeSocketKind::HttpRequest(..) => WasiSocketStatus::Opened, + InodeSocketKind::TcpListener(_) => WasiSocketStatus::Opened, + InodeSocketKind::TcpStream(_) => WasiSocketStatus::Opened, + InodeSocketKind::UdpSocket(_) => WasiSocketStatus::Opened, + InodeSocketKind::Closed => WasiSocketStatus::Closed, + _ => WasiSocketStatus::Failed, + }) } pub fn http_status(&self) -> Result { - Ok( - match &self.kind { - InodeSocketKind::HttpRequest(http, ..) => { - let http = http.lock().unwrap(); - let guard = http.status.lock().unwrap(); - let status = guard.recv() - .map_err(|_| __WASI_EIO)? - .map_err(net_error_into_wasi_err)?; - WasiHttpStatus { - ok: true, - redirected: status.redirected, - status: status.status, - size: status.size as u64, - } - }, - InodeSocketKind::Closed => return Err(__WASI_EIO), - _ => return Err(__WASI_ENOTSUP), + Ok(match &self.kind { + InodeSocketKind::HttpRequest(http, ..) => { + let http = http.lock().unwrap(); + let guard = http.status.lock().unwrap(); + let status = guard + .recv() + .map_err(|_| __WASI_EIO)? + .map_err(net_error_into_wasi_err)?; + WasiHttpStatus { + ok: true, + redirected: status.redirected, + status: status.status, + size: status.size as u64, + } } - ) + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + }) } pub fn addr_local(&self) -> Result { - Ok( - match &self.kind { - InodeSocketKind::PreSocket { family, addr, .. } => { - if let Some(addr) = addr { - addr.clone() - } else { - SocketAddr::new( - match family { - &__WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), - &__WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), - _ => return Err(__WASI_EINVAL) - }, - 0 - ) - } - }, - InodeSocketKind::Icmp(sock) => { - sock.addr_local() - .map_err(net_error_into_wasi_err)? - }, - InodeSocketKind::TcpListener(sock) => { - sock.addr_local() - .map_err(net_error_into_wasi_err)? - }, - InodeSocketKind::TcpStream(sock) => { - sock.addr_local() - .map_err(net_error_into_wasi_err)? - }, - InodeSocketKind::UdpSocket(sock) => { - sock.addr_local() - .map_err(net_error_into_wasi_err)? - }, - InodeSocketKind::Closed => return Err(__WASI_EIO), - _ => return Err(__WASI_ENOTSUP), - } - ) - } - - pub fn addr_peer(&self) -> Result { - Ok( - match &self.kind { - InodeSocketKind::PreSocket { family, .. } => { + Ok(match &self.kind { + InodeSocketKind::PreSocket { family, addr, .. } => { + if let Some(addr) = addr { + addr.clone() + } else { SocketAddr::new( match family { &__WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), &__WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), - _ => return Err(__WASI_EINVAL) + _ => return Err(__WASI_EINVAL), }, - 0 + 0, ) + } + } + InodeSocketKind::Icmp(sock) => sock.addr_local().map_err(net_error_into_wasi_err)?, + InodeSocketKind::TcpListener(sock) => { + sock.addr_local().map_err(net_error_into_wasi_err)? + } + InodeSocketKind::TcpStream(sock) => { + sock.addr_local().map_err(net_error_into_wasi_err)? + } + InodeSocketKind::UdpSocket(sock) => { + sock.addr_local().map_err(net_error_into_wasi_err)? + } + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + }) + } + + pub fn addr_peer(&self) -> Result { + Ok(match &self.kind { + InodeSocketKind::PreSocket { family, .. } => SocketAddr::new( + match family { + &__WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + &__WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + _ => return Err(__WASI_EINVAL), }, - InodeSocketKind::TcpStream(sock) => { - sock.addr_peer() - .map_err(net_error_into_wasi_err)? - }, - InodeSocketKind::UdpSocket(sock) => { - sock.addr_peer() - .map_err(net_error_into_wasi_err)? - .map(|addr| Ok(addr)) - .unwrap_or_else(|| { - sock.addr_local() - .map_err(net_error_into_wasi_err) - .map(|addr| { - SocketAddr::new( - match addr { - SocketAddr::V4(_) => IpAddr::V4(Ipv4Addr::UNSPECIFIED), - SocketAddr::V6(_) => IpAddr::V6(Ipv6Addr::UNSPECIFIED), - }, - 0 - ) - }) - })? - }, - InodeSocketKind::Closed => return Err(__WASI_EIO), - _ => return Err(__WASI_ENOTSUP), + 0, + ), + InodeSocketKind::TcpStream(sock) => { + sock.addr_peer().map_err(net_error_into_wasi_err)? } - ) + InodeSocketKind::UdpSocket(sock) => sock + .addr_peer() + .map_err(net_error_into_wasi_err)? + .map(|addr| Ok(addr)) + .unwrap_or_else(|| { + sock.addr_local() + .map_err(net_error_into_wasi_err) + .map(|addr| { + SocketAddr::new( + match addr { + SocketAddr::V4(_) => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + SocketAddr::V6(_) => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + }, + 0, + ) + }) + })?, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + }) } - pub fn set_opt_flag(&mut self, option: WasiSocketOption, val: bool) -> Result<(), __wasi_errno_t> { + pub fn set_opt_flag( + &mut self, + option: WasiSocketOption, + val: bool, + ) -> Result<(), __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::PreSocket { only_v6, reuse_port, reuse_addr, .. } => { + InodeSocketKind::PreSocket { + only_v6, + reuse_port, + reuse_addr, + .. + } => { match option { WasiSocketOption::OnlyV6 => *only_v6 = val, WasiSocketOption::ReusePort => *reuse_port = val, WasiSocketOption::ReuseAddr => *reuse_addr = val, - _ => return Err(__WASI_EINVAL) + _ => return Err(__WASI_EINVAL), }; - }, - InodeSocketKind::Raw(sock) => { - match option { - WasiSocketOption::Promiscuous => sock.set_promiscuous(val).map_err(net_error_into_wasi_err)?, - _ => return Err(__WASI_EINVAL) + } + InodeSocketKind::Raw(sock) => match option { + WasiSocketOption::Promiscuous => { + sock.set_promiscuous(val).map_err(net_error_into_wasi_err)? } + _ => return Err(__WASI_EINVAL), }, - InodeSocketKind::TcpStream(sock) => { - match option { - WasiSocketOption::NoDelay => sock.set_nodelay(val).map_err(net_error_into_wasi_err)?, - _ => return Err(__WASI_EINVAL) + InodeSocketKind::TcpStream(sock) => match option { + WasiSocketOption::NoDelay => { + sock.set_nodelay(val).map_err(net_error_into_wasi_err)? } + _ => return Err(__WASI_EINVAL), }, - InodeSocketKind::UdpSocket(sock) => { - match option { - WasiSocketOption::Broadcast => sock.set_broadcast(val).map_err(net_error_into_wasi_err)?, - WasiSocketOption::MulticastLoopV4 => sock.set_multicast_loop_v4(val).map_err(net_error_into_wasi_err)?, - WasiSocketOption::MulticastLoopV6 => sock.set_multicast_loop_v6(val).map_err(net_error_into_wasi_err)?, - _ => return Err(__WASI_EINVAL) + InodeSocketKind::UdpSocket(sock) => match option { + WasiSocketOption::Broadcast => { + sock.set_broadcast(val).map_err(net_error_into_wasi_err)? } + WasiSocketOption::MulticastLoopV4 => sock + .set_multicast_loop_v4(val) + .map_err(net_error_into_wasi_err)?, + WasiSocketOption::MulticastLoopV6 => sock + .set_multicast_loop_v6(val) + .map_err(net_error_into_wasi_err)?, + _ => return Err(__WASI_EINVAL), }, InodeSocketKind::Closed => return Err(__WASI_EIO), _ => return Err(__WASI_ENOTSUP), @@ -479,50 +478,52 @@ impl InodeSocket } pub fn get_opt_flag(&self, option: WasiSocketOption) -> Result { - Ok( - match &self.kind { - InodeSocketKind::PreSocket { only_v6, reuse_port, reuse_addr, .. } => { - match option { - WasiSocketOption::OnlyV6 => *only_v6, - WasiSocketOption::ReusePort => *reuse_port, - WasiSocketOption::ReuseAddr => *reuse_addr, - _ => return Err(__WASI_EINVAL) - } - }, - InodeSocketKind::Raw(sock) => { - match option { - WasiSocketOption::Promiscuous => sock.promiscuous().map_err(net_error_into_wasi_err)?, - _ => return Err(__WASI_EINVAL) - } - }, - InodeSocketKind::TcpStream(sock) => { - match option { - WasiSocketOption::NoDelay => sock.nodelay().map_err(net_error_into_wasi_err)?, - _ => return Err(__WASI_EINVAL) - } - }, - InodeSocketKind::UdpSocket(sock) => { - match option { - WasiSocketOption::Broadcast => sock.broadcast().map_err(net_error_into_wasi_err)?, - WasiSocketOption::MulticastLoopV4 => sock.multicast_loop_v4().map_err(net_error_into_wasi_err)?, - WasiSocketOption::MulticastLoopV6 => sock.multicast_loop_v6().map_err(net_error_into_wasi_err)?, - _ => return Err(__WASI_EINVAL) - } - }, - InodeSocketKind::Closed => return Err(__WASI_EIO), - _ => return Err(__WASI_ENOTSUP), - } - ) + Ok(match &self.kind { + InodeSocketKind::PreSocket { + only_v6, + reuse_port, + reuse_addr, + .. + } => match option { + WasiSocketOption::OnlyV6 => *only_v6, + WasiSocketOption::ReusePort => *reuse_port, + WasiSocketOption::ReuseAddr => *reuse_addr, + _ => return Err(__WASI_EINVAL), + }, + InodeSocketKind::Raw(sock) => match option { + WasiSocketOption::Promiscuous => { + sock.promiscuous().map_err(net_error_into_wasi_err)? + } + _ => return Err(__WASI_EINVAL), + }, + InodeSocketKind::TcpStream(sock) => match option { + WasiSocketOption::NoDelay => sock.nodelay().map_err(net_error_into_wasi_err)?, + _ => return Err(__WASI_EINVAL), + }, + InodeSocketKind::UdpSocket(sock) => match option { + WasiSocketOption::Broadcast => sock.broadcast().map_err(net_error_into_wasi_err)?, + WasiSocketOption::MulticastLoopV4 => { + sock.multicast_loop_v4().map_err(net_error_into_wasi_err)? + } + WasiSocketOption::MulticastLoopV6 => { + sock.multicast_loop_v6().map_err(net_error_into_wasi_err)? + } + _ => return Err(__WASI_EINVAL), + }, + InodeSocketKind::Closed => return Err(__WASI_EIO), + _ => return Err(__WASI_ENOTSUP), + }) } pub fn set_send_buf_size(&mut self, size: usize) -> Result<(), __wasi_errno_t> { match &mut self.kind { InodeSocketKind::PreSocket { send_buf_size, .. } => { *send_buf_size = Some(size); - }, + } InodeSocketKind::TcpStream(sock) => { - sock.set_send_buf_size(size).map_err(net_error_into_wasi_err)?; - }, + sock.set_send_buf_size(size) + .map_err(net_error_into_wasi_err)?; + } InodeSocketKind::Closed => return Err(__WASI_EIO), _ => return Err(__WASI_ENOTSUP), } @@ -533,10 +534,10 @@ impl InodeSocket match &self.kind { InodeSocketKind::PreSocket { send_buf_size, .. } => { Ok(send_buf_size.clone().unwrap_or_default()) - }, + } InodeSocketKind::TcpStream(sock) => { sock.send_buf_size().map_err(net_error_into_wasi_err) - }, + } InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } @@ -546,10 +547,11 @@ impl InodeSocket match &mut self.kind { InodeSocketKind::PreSocket { recv_buf_size, .. } => { *recv_buf_size = Some(size); - }, + } InodeSocketKind::TcpStream(sock) => { - sock.set_recv_buf_size(size).map_err(net_error_into_wasi_err)?; - }, + sock.set_recv_buf_size(size) + .map_err(net_error_into_wasi_err)?; + } InodeSocketKind::Closed => return Err(__WASI_EIO), _ => return Err(__WASI_ENOTSUP), } @@ -560,93 +562,102 @@ impl InodeSocket match &self.kind { InodeSocketKind::PreSocket { recv_buf_size, .. } => { Ok(recv_buf_size.clone().unwrap_or_default()) - }, + } InodeSocketKind::TcpStream(sock) => { sock.recv_buf_size().map_err(net_error_into_wasi_err) - }, + } InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - pub fn set_linger(&mut self, linger: Option) -> Result<(), __wasi_errno_t> { + pub fn set_linger( + &mut self, + linger: Option, + ) -> Result<(), __wasi_errno_t> { match &mut self.kind { InodeSocketKind::TcpStream(sock) => { sock.set_linger(linger).map_err(net_error_into_wasi_err) - }, + } InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - + pub fn linger(&self) -> Result, __wasi_errno_t> { match &self.kind { - InodeSocketKind::TcpStream(sock) => { - sock.linger().map_err(net_error_into_wasi_err) - }, + InodeSocketKind::TcpStream(sock) => sock.linger().map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - pub fn set_opt_time(&mut self, ty: TimeType, timeout: Option) -> Result<(), __wasi_errno_t> { + pub fn set_opt_time( + &mut self, + ty: TimeType, + timeout: Option, + ) -> Result<(), __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::TcpStream(sock) => { - sock.set_opt_time(ty, timeout).map_err(net_error_into_wasi_err) - }, - InodeSocketKind::TcpListener(sock) => { - match ty { - TimeType::AcceptTimeout => sock.set_timeout(timeout).map_err(net_error_into_wasi_err), - _ => Err(__WASI_EINVAL) + InodeSocketKind::TcpStream(sock) => sock + .set_opt_time(ty, timeout) + .map_err(net_error_into_wasi_err), + InodeSocketKind::TcpListener(sock) => match ty { + TimeType::AcceptTimeout => { + sock.set_timeout(timeout).map_err(net_error_into_wasi_err) } + _ => Err(__WASI_EINVAL), }, - InodeSocketKind::PreSocket { recv_timeout, send_timeout, connect_timeout, accept_timeout, .. } => { - match ty { - TimeType::ConnectTimeout => { - *connect_timeout = timeout; - Ok(()) - } - TimeType::AcceptTimeout => { - *accept_timeout = timeout; - Ok(()) - } - TimeType::ReadTimeout => { - *recv_timeout = timeout; - Ok(()) - } - TimeType::WriteTimeout => { - *send_timeout = timeout; - Ok(()) - } - _ => Err(__WASI_EIO) + InodeSocketKind::PreSocket { + recv_timeout, + send_timeout, + connect_timeout, + accept_timeout, + .. + } => match ty { + TimeType::ConnectTimeout => { + *connect_timeout = timeout; + Ok(()) + } + TimeType::AcceptTimeout => { + *accept_timeout = timeout; + Ok(()) + } + TimeType::ReadTimeout => { + *recv_timeout = timeout; + Ok(()) } + TimeType::WriteTimeout => { + *send_timeout = timeout; + Ok(()) + } + _ => Err(__WASI_EIO), }, InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - + pub fn opt_time(&self, ty: TimeType) -> Result, __wasi_errno_t> { match &self.kind { - InodeSocketKind::TcpStream(sock) => { - sock.opt_time(ty).map_err(net_error_into_wasi_err) - }, - InodeSocketKind::TcpListener(sock) => { - match ty { - TimeType::AcceptTimeout => sock.timeout().map_err(net_error_into_wasi_err), - _ => Err(__WASI_EINVAL) - } + InodeSocketKind::TcpStream(sock) => sock.opt_time(ty).map_err(net_error_into_wasi_err), + InodeSocketKind::TcpListener(sock) => match ty { + TimeType::AcceptTimeout => sock.timeout().map_err(net_error_into_wasi_err), + _ => Err(__WASI_EINVAL), }, - InodeSocketKind::PreSocket { recv_timeout, send_timeout, connect_timeout, accept_timeout, .. } => { - match ty { - TimeType::ConnectTimeout => Ok(connect_timeout.clone()), - TimeType::AcceptTimeout => Ok(accept_timeout.clone()), - TimeType::ReadTimeout => Ok(recv_timeout.clone()), - TimeType::WriteTimeout => Ok(send_timeout.clone()), - _ => Err(__WASI_EINVAL) - } + InodeSocketKind::PreSocket { + recv_timeout, + send_timeout, + connect_timeout, + accept_timeout, + .. + } => match ty { + TimeType::ConnectTimeout => Ok(connect_timeout.clone()), + TimeType::AcceptTimeout => Ok(accept_timeout.clone()), + TimeType::ReadTimeout => Ok(recv_timeout.clone()), + TimeType::WriteTimeout => Ok(send_timeout.clone()), + _ => Err(__WASI_EINVAL), }, InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), @@ -655,26 +666,18 @@ impl InodeSocket pub fn set_ttl(&mut self, ttl: u32) -> Result<(), __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::TcpStream(sock) => { - sock.set_ttl(ttl).map_err(net_error_into_wasi_err) - } - InodeSocketKind::UdpSocket(sock) => { - sock.set_ttl(ttl).map_err(net_error_into_wasi_err) - } + InodeSocketKind::TcpStream(sock) => sock.set_ttl(ttl).map_err(net_error_into_wasi_err), + InodeSocketKind::UdpSocket(sock) => sock.set_ttl(ttl).map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - + pub fn ttl(&self) -> Result { match &self.kind { - InodeSocketKind::TcpStream(sock) => { - sock.ttl().map_err(net_error_into_wasi_err) - } - InodeSocketKind::UdpSocket(sock) => { - sock.ttl().map_err(net_error_into_wasi_err) - } + InodeSocketKind::TcpStream(sock) => sock.ttl().map_err(net_error_into_wasi_err), + InodeSocketKind::UdpSocket(sock) => sock.ttl().map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), @@ -683,15 +686,15 @@ impl InodeSocket pub fn set_multicast_ttl_v4(&mut self, ttl: u32) -> Result<(), __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::UdpSocket(sock) => { - sock.set_multicast_ttl_v4(ttl).map_err(net_error_into_wasi_err) - } + InodeSocketKind::UdpSocket(sock) => sock + .set_multicast_ttl_v4(ttl) + .map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - + pub fn multicast_ttl_v4(&self) -> Result { match &self.kind { InodeSocketKind::UdpSocket(sock) => { @@ -702,53 +705,77 @@ impl InodeSocket _ => Err(__WASI_ENOTSUP), } } - - pub fn join_multicast_v4(&mut self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), __wasi_errno_t> { + + pub fn join_multicast_v4( + &mut self, + multiaddr: Ipv4Addr, + iface: Ipv4Addr, + ) -> Result<(), __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::UdpSocket(sock) => { - sock.join_multicast_v4(multiaddr, iface).map_err(net_error_into_wasi_err) - } + InodeSocketKind::UdpSocket(sock) => sock + .join_multicast_v4(multiaddr, iface) + .map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - - pub fn leave_multicast_v4(&mut self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), __wasi_errno_t> { + + pub fn leave_multicast_v4( + &mut self, + multiaddr: Ipv4Addr, + iface: Ipv4Addr, + ) -> Result<(), __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::UdpSocket(sock) => { - sock.leave_multicast_v4(multiaddr, iface).map_err(net_error_into_wasi_err) - } + InodeSocketKind::UdpSocket(sock) => sock + .leave_multicast_v4(multiaddr, iface) + .map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - - pub fn join_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), __wasi_errno_t> { + + pub fn join_multicast_v6( + &mut self, + multiaddr: Ipv6Addr, + iface: u32, + ) -> Result<(), __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::UdpSocket(sock) => { - sock.join_multicast_v6(multiaddr, iface).map_err(net_error_into_wasi_err) - } + InodeSocketKind::UdpSocket(sock) => sock + .join_multicast_v6(multiaddr, iface) + .map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - pub fn leave_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), __wasi_errno_t> { + pub fn leave_multicast_v6( + &mut self, + multiaddr: Ipv6Addr, + iface: u32, + ) -> Result<(), __wasi_errno_t> { match &mut self.kind { - InodeSocketKind::UdpSocket(sock) => { - sock.leave_multicast_v6(multiaddr, iface).map_err(net_error_into_wasi_err) - } + InodeSocketKind::UdpSocket(sock) => sock + .leave_multicast_v6(multiaddr, iface) + .map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_EIO), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), } } - pub fn send(&mut self, memory: &Memory, iov: WasmSlice<__wasi_ciovec_t>) -> Result { - let buf_len: M::Offset = iov.iter().filter_map(|a| a.read().ok()).map(|a| a.buf_len).sum(); + pub fn send( + &mut self, + memory: &Memory, + iov: WasmSlice<__wasi_ciovec_t>, + ) -> Result { + let buf_len: M::Offset = iov + .iter() + .filter_map(|a| a.read().ok()) + .map(|a| a.buf_len) + .sum(); let buf_len: usize = buf_len.try_into().map_err(|_| __WASI_EINVAL)?; let mut buf = Vec::with_capacity(buf_len); write_bytes(&mut buf, memory, iov)?; @@ -757,23 +784,35 @@ impl InodeSocket let sock = sock.lock().unwrap(); match ty { InodeHttpSocketType::Request => { - if sock.request.is_none() { return Err(__WASI_EIO); } + if sock.request.is_none() { + return Err(__WASI_EIO); + } let request = sock.request.as_ref().unwrap(); request.send(buf).map(|_| buf_len).map_err(|_| __WASI_EIO) - }, + } _ => { return Err(__WASI_EIO); } } - }, - InodeSocketKind::WebSocket(sock) => sock.send(Bytes::from(buf)).map(|_| buf_len).map_err(net_error_into_wasi_err), - InodeSocketKind::Raw(sock) => sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err), - InodeSocketKind::TcpStream(sock) => sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err), - InodeSocketKind::UdpSocket(sock) => sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err), + } + InodeSocketKind::WebSocket(sock) => sock + .send(Bytes::from(buf)) + .map(|_| buf_len) + .map_err(net_error_into_wasi_err), + InodeSocketKind::Raw(sock) => { + sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err) + } + InodeSocketKind::TcpStream(sock) => { + sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err) + } + InodeSocketKind::UdpSocket(sock) => { + sock.send(Bytes::from(buf)).map_err(net_error_into_wasi_err) + } InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), - }.map(|_| buf_len) + } + .map(|_| buf_len) } pub fn send_bytes(&mut self, buf: Bytes) -> Result { @@ -783,49 +822,75 @@ impl InodeSocket let sock = sock.lock().unwrap(); match ty { InodeHttpSocketType::Request => { - if sock.request.is_none() { return Err(__WASI_EIO); } + if sock.request.is_none() { + return Err(__WASI_EIO); + } let request = sock.request.as_ref().unwrap(); - request.send(buf.to_vec()).map(|_| buf_len).map_err(|_| __WASI_EIO) - }, + request + .send(buf.to_vec()) + .map(|_| buf_len) + .map_err(|_| __WASI_EIO) + } _ => { return Err(__WASI_EIO); } } - }, - InodeSocketKind::WebSocket(sock) => sock.send(buf).map(|_| buf_len).map_err(net_error_into_wasi_err), + } + InodeSocketKind::WebSocket(sock) => sock + .send(buf) + .map(|_| buf_len) + .map_err(net_error_into_wasi_err), InodeSocketKind::Raw(sock) => sock.send(buf).map_err(net_error_into_wasi_err), InodeSocketKind::TcpStream(sock) => sock.send(buf).map_err(net_error_into_wasi_err), InodeSocketKind::UdpSocket(sock) => sock.send(buf).map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), - }.map(|_| buf_len) + } + .map(|_| buf_len) } - pub fn send_to(&mut self, memory: &Memory, iov: WasmSlice<__wasi_ciovec_t>, addr: WasmPtr<__wasi_addr_port_t, M>) -> Result { + pub fn send_to( + &mut self, + memory: &Memory, + iov: WasmSlice<__wasi_ciovec_t>, + addr: WasmPtr<__wasi_addr_port_t, M>, + ) -> Result { let (addr_ip, addr_port) = read_ip_port(memory, addr)?; let addr = SocketAddr::new(addr_ip, addr_port); - let buf_len: M::Offset = iov.iter().filter_map(|a| a.read().ok()).map(|a| a.buf_len).sum(); + let buf_len: M::Offset = iov + .iter() + .filter_map(|a| a.read().ok()) + .map(|a| a.buf_len) + .sum(); let buf_len: usize = buf_len.try_into().map_err(|_| __WASI_EINVAL)?; let mut buf = Vec::with_capacity(buf_len); write_bytes(&mut buf, memory, iov)?; match &mut self.kind { - InodeSocketKind::Icmp(sock) => sock.send_to(Bytes::from(buf), addr).map_err(net_error_into_wasi_err), - InodeSocketKind::UdpSocket(sock) => sock.send_to(Bytes::from(buf), addr).map_err(net_error_into_wasi_err), + InodeSocketKind::Icmp(sock) => sock + .send_to(Bytes::from(buf), addr) + .map_err(net_error_into_wasi_err), + InodeSocketKind::UdpSocket(sock) => sock + .send_to(Bytes::from(buf), addr) + .map_err(net_error_into_wasi_err), InodeSocketKind::PreSocket { .. } => Err(__WASI_ENOTCONN), InodeSocketKind::Closed => Err(__WASI_EIO), _ => Err(__WASI_ENOTSUP), - }.map(|_| buf_len) + } + .map(|_| buf_len) } - pub fn recv(&mut self, memory: &Memory, iov: WasmSlice<__wasi_iovec_t>) -> Result { + pub fn recv( + &mut self, + memory: &Memory, + iov: WasmSlice<__wasi_iovec_t>, + ) -> Result { loop { if let Some(buf) = self.read_buffer.as_mut() { let buf_len = buf.len(); if buf_len > 0 { let reader = buf.as_ref(); - let read = read_bytes(reader, memory, iov) - .map(|_| buf_len)?; + let read = read_bytes(reader, memory, iov).map(|_| buf_len)?; if let InodeSocketKind::TcpStream(..) = &self.kind { buf.advance(read); } else { @@ -839,38 +904,42 @@ impl InodeSocket let sock = sock.lock().unwrap(); match ty { InodeHttpSocketType::Response => { - if sock.response.is_none() { return Err(__WASI_EIO); } + if sock.response.is_none() { + return Err(__WASI_EIO); + } let response = sock.response.as_ref().unwrap(); Bytes::from(response.recv().map_err(|_| __WASI_EIO)?) - }, + } InodeHttpSocketType::Headers => { - if sock.headers.is_none() { return Err(__WASI_EIO); } + if sock.headers.is_none() { + return Err(__WASI_EIO); + } let headers = sock.headers.as_ref().unwrap(); let headers = headers.recv().map_err(|_| __WASI_EIO)?; let headers = format!("{}: {}", headers.0, headers.1); Bytes::from(headers.as_bytes().to_vec()) - }, + } _ => { return Err(__WASI_EIO); } } - }, + } InodeSocketKind::WebSocket(sock) => { let read = sock.recv().map_err(net_error_into_wasi_err)?; read.data - }, + } InodeSocketKind::Raw(sock) => { let read = sock.recv().map_err(net_error_into_wasi_err)?; read.data - }, + } InodeSocketKind::TcpStream(sock) => { let read = sock.recv().map_err(net_error_into_wasi_err)?; read.data - }, + } InodeSocketKind::UdpSocket(sock) => { let read = sock.recv().map_err(net_error_into_wasi_err)?; read.data - }, + } InodeSocketKind::PreSocket { .. } => return Err(__WASI_ENOTCONN), InodeSocketKind::Closed => return Err(__WASI_EIO), _ => return Err(__WASI_ENOTSUP), @@ -880,24 +949,30 @@ impl InodeSocket } } - pub fn recv_from(&mut self, memory: &Memory, iov: WasmSlice<__wasi_iovec_t>, addr: WasmPtr<__wasi_addr_port_t, M>) -> Result { + pub fn recv_from( + &mut self, + memory: &Memory, + iov: WasmSlice<__wasi_iovec_t>, + addr: WasmPtr<__wasi_addr_port_t, M>, + ) -> Result { loop { if let Some(buf) = self.read_buffer.as_mut() { if buf.len() > 0 { let reader = buf.as_ref(); let ret = read_bytes(reader, memory, iov)?; - let peer = self.read_addr.clone().unwrap_or_else(|| SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)); + let peer = self + .read_addr + .clone() + .unwrap_or_else(|| SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)); write_ip_port(memory, addr, peer.ip(), peer.port())?; return Ok(ret); } } let rcv = match &mut self.kind { - InodeSocketKind::Icmp(sock) => { - sock.recv_from().map_err(net_error_into_wasi_err)? - }, + InodeSocketKind::Icmp(sock) => sock.recv_from().map_err(net_error_into_wasi_err)?, InodeSocketKind::UdpSocket(sock) => { sock.recv_from().map_err(net_error_into_wasi_err)? - }, + } InodeSocketKind::PreSocket { .. } => return Err(__WASI_ENOTCONN), InodeSocketKind::Closed => return Err(__WASI_EIO), _ => return Err(__WASI_ENOTSUP), @@ -912,24 +987,24 @@ impl InodeSocket match &mut self.kind { InodeSocketKind::TcpStream(sock) => { sock.shutdown(how).map_err(net_error_into_wasi_err)?; - }, + } InodeSocketKind::HttpRequest(http, ..) => { let mut http = http.lock().unwrap(); match how { Shutdown::Read => { http.response.take(); http.headers.take(); - }, + } Shutdown::Write => { http.request.take(); - }, + } Shutdown::Both => { http.request.take(); http.response.take(); http.headers.take(); - }, + } }; - }, + } InodeSocketKind::PreSocket { .. } => return Err(__WASI_ENOTCONN), InodeSocketKind::Closed => return Err(__WASI_EIO), _ => return Err(__WASI_ENOTSUP), @@ -938,9 +1013,7 @@ impl InodeSocket } } -impl Read -for InodeSocket -{ +impl Read for InodeSocket { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { loop { if let Some(read_buf) = self.read_buffer.as_mut() { @@ -957,29 +1030,37 @@ for InodeSocket let sock = sock.lock().unwrap(); match ty { InodeHttpSocketType::Response => { - if sock.response.is_none() { return Err(io::Error::new( - io::ErrorKind::BrokenPipe, - format!("the socket is not connected"), - )); } + if sock.response.is_none() { + return Err(io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the socket is not connected"), + )); + } let response = sock.response.as_ref().unwrap(); - Bytes::from(response.recv().map_err(|_| io::Error::new( - io::ErrorKind::BrokenPipe, - format!("the wasi pipe is not connected"), - ))?) - }, + Bytes::from(response.recv().map_err(|_| { + io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the wasi pipe is not connected"), + ) + })?) + } InodeHttpSocketType::Headers => { - if sock.headers.is_none() { return Err(io::Error::new( - io::ErrorKind::BrokenPipe, - format!("the socket is not connected"), - )); } + if sock.headers.is_none() { + return Err(io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the socket is not connected"), + )); + } let headers = sock.headers.as_ref().unwrap(); - let headers = headers.recv().map_err(|_| io::Error::new( - io::ErrorKind::BrokenPipe, - format!("the wasi pipe is not connected"), - ))?; + let headers = headers.recv().map_err(|_| { + io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the wasi pipe is not connected"), + ) + })?; let headers = format!("{}: {}", headers.0, headers.1); Bytes::from(headers.as_bytes().to_vec()) - }, + } _ => { return Err(io::Error::new( io::ErrorKind::Unsupported, @@ -987,35 +1068,41 @@ for InodeSocket )); } } - }, + } InodeSocketKind::WebSocket(sock) => { let read = sock.recv().map_err(net_error_into_io_err)?; read.data - }, + } InodeSocketKind::Raw(sock) => { let read = sock.recv().map_err(net_error_into_io_err)?; read.data - }, + } InodeSocketKind::TcpStream(sock) => { let read = sock.recv().map_err(net_error_into_io_err)?; read.data - }, + } InodeSocketKind::UdpSocket(sock) => { let read = sock.recv().map_err(net_error_into_io_err)?; read.data - }, - InodeSocketKind::PreSocket { .. } => return Err(io::Error::new( - io::ErrorKind::NotConnected, - format!("the socket is not connected"), - )), - InodeSocketKind::Closed => return Err(io::Error::new( - io::ErrorKind::BrokenPipe, - format!("the socket has been closed"), - )), - _ => return Err(io::Error::new( - io::ErrorKind::Unsupported, - format!("the socket type is not supported"), - )), + } + InodeSocketKind::PreSocket { .. } => { + return Err(io::Error::new( + io::ErrorKind::NotConnected, + format!("the socket is not connected"), + )) + } + InodeSocketKind::Closed => { + return Err(io::Error::new( + io::ErrorKind::BrokenPipe, + format!("the socket has been closed"), + )) + } + _ => { + return Err(io::Error::new( + io::ErrorKind::Unsupported, + format!("the socket type is not supported"), + )) + } }; self.read_buffer.replace(data); self.read_addr.take(); @@ -1023,9 +1110,7 @@ for InodeSocket } } -impl Drop -for InodeSocket -{ +impl Drop for InodeSocket { fn drop(&mut self) { match &self.kind { InodeSocketKind::HttpRequest(http, ty) => { @@ -1033,78 +1118,81 @@ for InodeSocket match ty { InodeHttpSocketType::Request => { guard.request.take(); - }, + } InodeHttpSocketType::Response => { guard.response.take(); - }, + } InodeHttpSocketType::Headers => { guard.headers.take(); } } - }, - _ => { } + } + _ => {} } } } #[allow(dead_code)] -pub(crate) fn read_ip(memory: &Memory, ptr: WasmPtr<__wasi_addr_t, M>) -> Result { +pub(crate) fn read_ip( + memory: &Memory, + ptr: WasmPtr<__wasi_addr_t, M>, +) -> Result { let addr_ptr = ptr.deref(memory); let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; let o = addr.u.octs; - Ok( - match addr.tag { - __WASI_ADDRESS_FAMILY_INET4 => { - IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])) - }, - __WASI_ADDRESS_FAMILY_INET6 => { - let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(o) }; - IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)) - }, - _ => return Err(__WASI_EINVAL) + Ok(match addr.tag { + __WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])), + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(o) }; + IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) } - ) + _ => return Err(__WASI_EINVAL), + }) } -pub(crate) fn read_ip_v4(memory: &Memory, ptr: WasmPtr<__wasi_addr_ip4_t, M>) -> Result { +pub(crate) fn read_ip_v4( + memory: &Memory, + ptr: WasmPtr<__wasi_addr_ip4_t, M>, +) -> Result { let addr_ptr = ptr.deref(memory); let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; let o = addr.octs; - Ok( - Ipv4Addr::new(o[0], o[1], o[2], o[3]) - ) + Ok(Ipv4Addr::new(o[0], o[1], o[2], o[3])) } -pub(crate) fn read_ip_v6(memory: &Memory, ptr: WasmPtr<__wasi_addr_ip6_t, M>) -> Result { +pub(crate) fn read_ip_v6( + memory: &Memory, + ptr: WasmPtr<__wasi_addr_ip6_t, M>, +) -> Result { let addr_ptr = ptr.deref(memory); let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(addr.segs) }; - Ok( - Ipv6Addr::new(a, b, c, d, e, f, g ,h) - ) + Ok(Ipv6Addr::new(a, b, c, d, e, f, g, h)) } -pub(crate) fn write_ip(memory: &Memory, ptr: WasmPtr<__wasi_addr_t, M>, ip: IpAddr) -> Result<(), __wasi_errno_t> { +pub(crate) fn write_ip( + memory: &Memory, + ptr: WasmPtr<__wasi_addr_t, M>, + ip: IpAddr, +) -> Result<(), __wasi_errno_t> { let ip = match ip { IpAddr::V4(ip) => { let o = ip.octets(); __wasi_addr_t { tag: __WASI_ADDRESS_FAMILY_INET4, u: __wasi_addr_u { - octs: [ o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - } + octs: [o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }, } - }, + } IpAddr::V6(ip) => { let o = ip.octets(); __wasi_addr_t { tag: __WASI_ADDRESS_FAMILY_INET6, - u: __wasi_addr_u { - octs: o - } + u: __wasi_addr_u { octs: o }, } } }; @@ -1115,36 +1203,42 @@ pub(crate) fn write_ip(memory: &Memory, ptr: WasmPtr<__wasi_addr_ } #[allow(dead_code)] -pub(crate) fn read_cidr(memory: &Memory, ptr: WasmPtr<__wasi_cidr_t, M>) -> Result { +pub(crate) fn read_cidr( + memory: &Memory, + ptr: WasmPtr<__wasi_cidr_t, M>, +) -> Result { let addr_ptr = ptr.deref(memory); let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; let o = addr.u.octs; - Ok( - match addr.tag { - __WASI_ADDRESS_FAMILY_INET4 => { - IpCidr { - ip: IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])), - prefix: o[4] - } - }, - __WASI_ADDRESS_FAMILY_INET6 => { - let [a, b, c, d, e, f, g, h] = { - let o = [ o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15] ]; - unsafe { transmute::<_, [u16; 8]>(o) } - }; - IpCidr { - ip: IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)), - prefix: o[16] - } - }, - _ => return Err(__WASI_EINVAL) + Ok(match addr.tag { + __WASI_ADDRESS_FAMILY_INET4 => IpCidr { + ip: IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])), + prefix: o[4], + }, + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = { + let o = [ + o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], + o[12], o[13], o[14], o[15], + ]; + unsafe { transmute::<_, [u16; 8]>(o) } + }; + IpCidr { + ip: IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)), + prefix: o[16], + } } - ) + _ => return Err(__WASI_EINVAL), + }) } #[allow(dead_code)] -pub(crate) fn write_cidr(memory: &Memory, ptr: WasmPtr<__wasi_cidr_t, M>, cidr: IpCidr) -> Result<(), __wasi_errno_t> { +pub(crate) fn write_cidr( + memory: &Memory, + ptr: WasmPtr<__wasi_cidr_t, M>, + cidr: IpCidr, +) -> Result<(), __wasi_errno_t> { let p = cidr.prefix; let cidr = match cidr.ip { IpAddr::V4(ip) => { @@ -1152,17 +1246,22 @@ pub(crate) fn write_cidr(memory: &Memory, ptr: WasmPtr<__wasi_cid __wasi_cidr_t { tag: __WASI_ADDRESS_FAMILY_INET4, u: __wasi_cidr_u { - octs: [ o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - } + octs: [ + o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }, } - }, + } IpAddr::V6(ip) => { let o = ip.octets(); __wasi_cidr_t { tag: __WASI_ADDRESS_FAMILY_INET6, u: __wasi_cidr_u { - octs: [ o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15], p ] - } + octs: [ + o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], + o[12], o[13], o[14], o[15], p, + ], + }, } } }; @@ -1172,37 +1271,43 @@ pub(crate) fn write_cidr(memory: &Memory, ptr: WasmPtr<__wasi_cid Ok(()) } -pub(crate) fn read_ip_port(memory: &Memory, ptr: WasmPtr<__wasi_addr_port_t, M>) -> Result<(IpAddr, u16), __wasi_errno_t> { +pub(crate) fn read_ip_port( + memory: &Memory, + ptr: WasmPtr<__wasi_addr_port_t, M>, +) -> Result<(IpAddr, u16), __wasi_errno_t> { let addr_ptr = ptr.deref(memory); let addr = addr_ptr.read().map_err(crate::mem_error_to_wasi)?; let o = addr.u.octs; - Ok( - match addr.tag { - __WASI_ADDRESS_FAMILY_INET4 => { - let port = u16::from_ne_bytes([ o[0], o[1] ]); - ( - IpAddr::V4(Ipv4Addr::new(o[2], o[3], o[4], o[5])), - port - ) - }, - __WASI_ADDRESS_FAMILY_INET6 => { - let [a, b, c, d, e, f, g, h] = { - let o = [ o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15], o[16], o[17] ]; - unsafe { transmute::<_, [u16; 8]>(o) } - }; - ( - IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)), - u16::from_ne_bytes([ o[0], o[1] ]) - ) - }, - _ => return Err(__WASI_EINVAL) + Ok(match addr.tag { + __WASI_ADDRESS_FAMILY_INET4 => { + let port = u16::from_ne_bytes([o[0], o[1]]); + (IpAddr::V4(Ipv4Addr::new(o[2], o[3], o[4], o[5])), port) } - ) + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = { + let o = [ + o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], + o[14], o[15], o[16], o[17], + ]; + unsafe { transmute::<_, [u16; 8]>(o) } + }; + ( + IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)), + u16::from_ne_bytes([o[0], o[1]]), + ) + } + _ => return Err(__WASI_EINVAL), + }) } #[allow(dead_code)] -pub(crate) fn write_ip_port(memory: &Memory, ptr: WasmPtr<__wasi_addr_port_t, M>, ip: IpAddr, port: u16) -> Result<(), __wasi_errno_t> { +pub(crate) fn write_ip_port( + memory: &Memory, + ptr: WasmPtr<__wasi_addr_port_t, M>, + ip: IpAddr, + port: u16, +) -> Result<(), __wasi_errno_t> { let p = port.to_be_bytes(); let ipport = match ip { IpAddr::V4(ip) => { @@ -1210,17 +1315,22 @@ pub(crate) fn write_ip_port(memory: &Memory, ptr: WasmPtr<__wasi_ __wasi_addr_port_t { tag: __WASI_ADDRESS_FAMILY_INET4, u: __wasi_addr_port_u { - octs: [ p[0], p[1], o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - } + octs: [ + p[0], p[1], o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }, } - }, + } IpAddr::V6(ip) => { let o = ip.octets(); __wasi_addr_port_t { tag: __WASI_ADDRESS_FAMILY_INET6, u: __wasi_addr_port_u { - octs: [ p[0], p[1], o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15] ] - } + octs: [ + p[0], p[1], o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], + o[10], o[11], o[12], o[13], o[14], o[15], + ], + }, } } }; @@ -1231,66 +1341,66 @@ pub(crate) fn write_ip_port(memory: &Memory, ptr: WasmPtr<__wasi_ } #[allow(dead_code)] -pub(crate) fn read_route(memory: &Memory, ptr: WasmPtr<__wasi_route_t, M>) -> Result { +pub(crate) fn read_route( + memory: &Memory, + ptr: WasmPtr<__wasi_route_t, M>, +) -> Result { let route_ptr = ptr.deref(memory); let route = route_ptr.read().map_err(crate::mem_error_to_wasi)?; - Ok( - IpRoute { - cidr: { - let o = route.cidr.u.octs; - match route.cidr.tag { - __WASI_ADDRESS_FAMILY_INET4 => { - IpCidr { - ip: IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])), - prefix: o[4] - } - }, - __WASI_ADDRESS_FAMILY_INET6 => { - let [a, b, c, d, e, f, g, h] = { - let o = [ o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15] ]; - unsafe { transmute::<_, [u16; 8]>(o) } - }; - IpCidr { - ip: IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)), - prefix: o[16] - } - }, - _ => return Err(__WASI_EINVAL) + Ok(IpRoute { + cidr: { + let o = route.cidr.u.octs; + match route.cidr.tag { + __WASI_ADDRESS_FAMILY_INET4 => IpCidr { + ip: IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])), + prefix: o[4], + }, + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = { + let o = [ + o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], + o[11], o[12], o[13], o[14], o[15], + ]; + unsafe { transmute::<_, [u16; 8]>(o) } + }; + IpCidr { + ip: IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)), + prefix: o[16], + } } - }, - via_router: { - let o = route.via_router.u.octs; - match route.via_router.tag { - __WASI_ADDRESS_FAMILY_INET4 => { - IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])) - }, - __WASI_ADDRESS_FAMILY_INET6 => { - let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(o) }; - IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g ,h)) - }, - _ => return Err(__WASI_EINVAL) + _ => return Err(__WASI_EINVAL), + } + }, + via_router: { + let o = route.via_router.u.octs; + match route.via_router.tag { + __WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::new(o[0], o[1], o[2], o[3])), + __WASI_ADDRESS_FAMILY_INET6 => { + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(o) }; + IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)) } - }, - preferred_until: match route.preferred_until.tag { - __WASI_OPTION_NONE => None, - __WASI_OPTION_SOME => Some( - Duration::from_nanos(route.preferred_until.u) - ), - _ => return Err(__WASI_EINVAL) - }, - expires_at: match route.expires_at.tag { - __WASI_OPTION_NONE => None, - __WASI_OPTION_SOME => Some( - Duration::from_nanos(route.expires_at.u) - ), - _ => return Err(__WASI_EINVAL) + _ => return Err(__WASI_EINVAL), } - } - ) + }, + preferred_until: match route.preferred_until.tag { + __WASI_OPTION_NONE => None, + __WASI_OPTION_SOME => Some(Duration::from_nanos(route.preferred_until.u)), + _ => return Err(__WASI_EINVAL), + }, + expires_at: match route.expires_at.tag { + __WASI_OPTION_NONE => None, + __WASI_OPTION_SOME => Some(Duration::from_nanos(route.expires_at.u)), + _ => return Err(__WASI_EINVAL), + }, + }) } -pub(crate) fn write_route(memory: &Memory, ptr: WasmPtr<__wasi_route_t, M>, route: IpRoute) -> Result<(), __wasi_errno_t> { +pub(crate) fn write_route( + memory: &Memory, + ptr: WasmPtr<__wasi_route_t, M>, + route: IpRoute, +) -> Result<(), __wasi_errno_t> { let cidr = { let p = route.cidr.prefix; match route.cidr.ip { @@ -1299,17 +1409,22 @@ pub(crate) fn write_route(memory: &Memory, ptr: WasmPtr<__wasi_ro __wasi_cidr_t { tag: __WASI_ADDRESS_FAMILY_INET4, u: __wasi_cidr_u { - octs: [ o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - } + octs: [ + o[0], o[1], o[2], o[3], p, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }, } - }, + } IpAddr::V6(ip) => { let o = ip.octets(); __wasi_cidr_t { tag: __WASI_ADDRESS_FAMILY_INET6, u: __wasi_cidr_u { - octs: [ o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], o[11], o[12], o[13], o[14], o[15], p ] - } + octs: [ + o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9], o[10], + o[11], o[12], o[13], o[14], o[15], p, + ], + }, } } } @@ -1320,46 +1435,44 @@ pub(crate) fn write_route(memory: &Memory, ptr: WasmPtr<__wasi_ro __wasi_addr_t { tag: __WASI_ADDRESS_FAMILY_INET4, u: __wasi_addr_u { - octs: [ o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - } + octs: [o[0], o[1], o[2], o[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }, } - }, + } IpAddr::V6(ip) => { let o = ip.octets(); __wasi_addr_t { tag: __WASI_ADDRESS_FAMILY_INET6, - u: __wasi_addr_u { - octs: o - } + u: __wasi_addr_u { octs: o }, } } }; let preferred_until = match route.preferred_until { None => __wasi_option_timestamp_t { tag: __WASI_OPTION_NONE, - u: 0 + u: 0, }, Some(u) => __wasi_option_timestamp_t { tag: __WASI_OPTION_SOME, - u: u.as_nanos() as u64 - } + u: u.as_nanos() as u64, + }, }; let expires_at = match route.expires_at { None => __wasi_option_timestamp_t { tag: __WASI_OPTION_NONE, - u: 0 + u: 0, }, Some(u) => __wasi_option_timestamp_t { tag: __WASI_OPTION_SOME, - u: u.as_nanos() as u64 - } + u: u.as_nanos() as u64, + }, }; let route = __wasi_route_t { cidr, via_router, preferred_until, - expires_at + expires_at, }; let route_ptr = ptr.deref(memory); @@ -1368,20 +1481,20 @@ pub(crate) fn write_route(memory: &Memory, ptr: WasmPtr<__wasi_ro } pub(crate) fn all_socket_rights() -> __wasi_rights_t { - __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | - __WASI_RIGHT_FD_FILESTAT_GET | - __WASI_RIGHT_FD_READ | - __WASI_RIGHT_FD_WRITE | - __WASI_RIGHT_POLL_FD_READWRITE | - __WASI_RIGHT_SOCK_SHUTDOWN | - __WASI_RIGHT_SOCK_CONNECT | - __WASI_RIGHT_SOCK_LISTEN | - __WASI_RIGHT_SOCK_BIND | - __WASI_RIGHT_SOCK_ACCEPT | - __WASI_RIGHT_SOCK_RECV | - __WASI_RIGHT_SOCK_SEND | - __WASI_RIGHT_SOCK_ADDR_LOCAL | - __WASI_RIGHT_SOCK_ADDR_REMOTE | - __WASI_RIGHT_SOCK_RECV_FROM | - __WASI_RIGHT_SOCK_SEND_TO + __WASI_RIGHT_FD_FDSTAT_SET_FLAGS + | __WASI_RIGHT_FD_FILESTAT_GET + | __WASI_RIGHT_FD_READ + | __WASI_RIGHT_FD_WRITE + | __WASI_RIGHT_POLL_FD_READWRITE + | __WASI_RIGHT_SOCK_SHUTDOWN + | __WASI_RIGHT_SOCK_CONNECT + | __WASI_RIGHT_SOCK_LISTEN + | __WASI_RIGHT_SOCK_BIND + | __WASI_RIGHT_SOCK_ACCEPT + | __WASI_RIGHT_SOCK_RECV + | __WASI_RIGHT_SOCK_SEND + | __WASI_RIGHT_SOCK_ADDR_LOCAL + | __WASI_RIGHT_SOCK_ADDR_REMOTE + | __WASI_RIGHT_SOCK_RECV_FROM + | __WASI_RIGHT_SOCK_SEND_TO } diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 996e81e3612..cba0b4de83f 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -5,9 +5,9 @@ use serde::{Deserialize, Serialize}; #[cfg(all(unix, feature = "sys-poll"))] use std::convert::TryInto; use std::{ - sync::{Arc, Mutex}, collections::VecDeque, io::{self, Read, Seek, Write}, + sync::{Arc, Mutex}, time::Duration, }; @@ -17,7 +17,7 @@ pub use wasmer_vfs::host_fs::{Stderr, Stdin, Stdout}; pub use wasmer_vfs::mem_fs::{Stderr, Stdin, Stdout}; use wasmer_vfs::{FsError, VirtualFile}; -use wasmer_vnet::{NetworkError}; +use wasmer_vnet::NetworkError; pub fn fs_error_from_wasi_err(err: __wasi_errno_t) -> FsError { match err { @@ -237,7 +237,13 @@ pub(crate) fn poll( revents: 0, }) .collect::>(); - let result = unsafe { libc::poll(fds.as_mut_ptr(), selfs.len() as _, timeout.as_millis() as i32) }; + let result = unsafe { + libc::poll( + fds.as_mut_ptr(), + selfs.len() as _, + timeout.as_millis() as i32, + ) + }; if result < 0 { // TODO: check errno and return value @@ -268,17 +274,19 @@ pub(crate) fn poll( let mut builder = PollEventBuilder::new(); let file = files[n]; - let can_read = file - .bytes_available_read()? - .map(|_| true) - .unwrap_or(false); + let can_read = file.bytes_available_read()?.map(|_| true).unwrap_or(false); let can_write = file .bytes_available_write()? .map(|s| s > 0) .unwrap_or(false); let is_closed = file.is_open() == false; - tracing::debug!("poll_evt can_read={} can_write={} is_closed={}", can_read, can_write, is_closed); + tracing::debug!( + "poll_evt can_read={} can_write={} is_closed={}", + can_read, + can_write, + is_closed + ); for event in iterate_poll_events(events[n]) { match event { diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index 249876712dd..374c180a1ad 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -1,6 +1,6 @@ use crate::syscalls; use crate::syscalls::types::{self, snapshot0}; -use crate::{mem_error_to_wasi, WasiEnv, WasiError, WasiThread, MemorySize, Memory32}; +use crate::{mem_error_to_wasi, Memory32, MemorySize, WasiEnv, WasiError, WasiThread}; use wasmer::WasmPtr; /// Wrapper around `syscalls::fd_filestat_get` with extra logic to handle the size @@ -72,7 +72,8 @@ pub fn path_filestat_get( let new_buf: WasmPtr = buf.cast(); let new_filestat_setup: types::__wasi_filestat_t = wasi_try_mem!(new_buf.read(memory)); - let result = syscalls::path_filestat_get::(thread, fd, flags, path, path_len, new_buf); + let result = + syscalls::path_filestat_get::(thread, fd, flags, path, path_len, new_buf); let memory = thread.memory(); let new_filestat = wasi_try_mem!(new_buf.deref(memory).read()); @@ -158,7 +159,8 @@ pub fn poll_oneoff( } // make the call - let result = syscalls::poll_oneoff::(thread, in_new_type_ptr, out_, nsubscriptions, nevents); + let result = + syscalls::poll_oneoff::(thread, in_new_type_ptr, out_, nsubscriptions, nevents); // replace the old values of in, in case the calling code reuses the memory let memory = thread.memory(); diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 979bb646d2a..f220aa0e7e4 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -27,28 +27,27 @@ use crate::utils::map_io_err; use crate::{ mem_error_to_wasi, state::{ - self, fs_error_into_wasi_err, net_error_into_wasi_err, iterate_poll_events, poll, - virtual_file_type_to_wasi_file_type, Fd, Inode, InodeVal, Kind, PollEvent, - PollEventBuilder, WasiState, MAX_SYMLINKS, InodeSocket, InodeSocketKind, - WasiPipe, + self, fs_error_into_wasi_err, iterate_poll_events, net_error_into_wasi_err, poll, + virtual_file_type_to_wasi_file_type, Fd, Inode, InodeSocket, InodeSocketKind, InodeVal, + Kind, PollEvent, PollEventBuilder, WasiPipe, WasiState, MAX_SYMLINKS, }, - WasiEnv, WasiError, WasiThread, WasiThreadId + WasiEnv, WasiError, WasiThread, WasiThreadId, }; +use bytes::Bytes; use std::borrow::Borrow; use std::convert::{Infallible, TryInto}; use std::io::{self, Read, Seek, Write}; -use std::sync::{Arc, mpsc}; +use std::mem::transmute; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::ops::{Deref, DerefMut}; use std::sync::atomic::AtomicU64; +use std::sync::{atomic::Ordering, Mutex}; +use std::sync::{mpsc, Arc}; use std::time::Duration; -use std::ops::{Deref, DerefMut}; -use std::sync::{Mutex, atomic::Ordering}; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; -use std::mem::transmute; -use bytes::Bytes; -use tracing::{debug, trace, error}; -use wasmer::{Memory, RuntimeError, Value, WasmPtr, WasmSlice, MemorySize, Memory32, Memory64}; +use tracing::{debug, error, trace}; +use wasmer::{Memory, Memory32, Memory64, MemorySize, RuntimeError, Value, WasmPtr, WasmSlice}; use wasmer_vfs::{FsError, VirtualFile}; -use wasmer_vnet::{StreamSecurity, SocketHttpRequest}; +use wasmer_vnet::{SocketHttpRequest, StreamSecurity}; #[cfg(any( target_os = "freebsd", @@ -64,14 +63,12 @@ pub use windows::*; #[cfg(any(target_arch = "wasm32"))] pub use wasm32::*; -fn to_offset(offset: usize) -> Result -{ +fn to_offset(offset: usize) -> Result { let ret: M::Offset = offset.try_into().map_err(|_| __WASI_EINVAL)?; Ok(ret) } -fn from_offset(offset: M::Offset) -> Result -{ +fn from_offset(offset: M::Offset) -> Result { let ret: usize = offset.try_into().map_err(|_| __WASI_EINVAL)?; Ok(ret) } @@ -139,9 +136,10 @@ fn __sock_actor( thread: &WasiThread, sock: __wasi_fd_t, rights: __wasi_rights_t, - actor: F + actor: F, ) -> Result -where F: FnOnce(&crate::state::InodeSocket) -> Result +where + F: FnOnce(&crate::state::InodeSocket) -> Result, { let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -158,9 +156,7 @@ where F: FnOnce(&crate::state::InodeSocket) -> Result let mut guard = inode.read(); match guard.deref() { - Kind::Socket { socket } => { - actor(socket)? - } + Kind::Socket { socket } => actor(socket)?, _ => { return Err(__WASI_ENOTSOCK); } @@ -174,9 +170,10 @@ fn __sock_actor_mut( thread: &WasiThread, sock: __wasi_fd_t, rights: __wasi_rights_t, - actor: F + actor: F, ) -> Result -where F: FnOnce(&mut crate::state::InodeSocket) -> Result +where + F: FnOnce(&mut crate::state::InodeSocket) -> Result, { let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -193,9 +190,7 @@ where F: FnOnce(&mut crate::state::InodeSocket) -> Result let mut guard = inode.write(); match guard.deref_mut() { - Kind::Socket { socket } => { - actor(socket)? - } + Kind::Socket { socket } => actor(socket)?, _ => { return Err(__WASI_ENOTSOCK); } @@ -209,9 +204,12 @@ fn __sock_upgrade( thread: &WasiThread, sock: __wasi_fd_t, rights: __wasi_rights_t, - actor: F + actor: F, ) -> Result<(), __wasi_errno_t> -where F: FnOnce(&mut crate::state::InodeSocket) -> Result, __wasi_errno_t> +where + F: FnOnce( + &mut crate::state::InodeSocket, + ) -> Result, __wasi_errno_t>, { let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); @@ -238,7 +236,7 @@ where F: FnOnce(&mut crate::state::InodeSocket) -> Result( let new_ptr = WasmPtr::new(buf_offset); wasi_try_mem!(ptr.write(new_ptr)); - let data = wasi_try_mem!(new_ptr.slice(memory, wasi_try!(to_offset::(sub_buffer.len())))); + let data = + wasi_try_mem!(new_ptr.slice(memory, wasi_try!(to_offset::(sub_buffer.len())))); wasi_try_mem!(data.write_slice(sub_buffer)); - wasi_try_mem!(wasi_try_mem!(new_ptr.add(wasi_try!(to_offset::(sub_buffer.len())))).write(memory, 0)); + wasi_try_mem!( + wasi_try_mem!(new_ptr.add_offset(wasi_try!(to_offset::(sub_buffer.len())))) + .write(memory, 0) + ); current_buffer_offset += sub_buffer.len() + 1; } @@ -330,7 +332,8 @@ pub fn args_sizes_get( let argc_val: M::Offset = wasi_try!(state.args.len().try_into().map_err(|_| __WASI_EOVERFLOW)); let argv_buf_size_val: usize = state.args.iter().map(|v| v.len() + 1).sum(); - let argv_buf_size_val: M::Offset = wasi_try!(argv_buf_size_val.try_into().map_err(|_| __WASI_EOVERFLOW)); + let argv_buf_size_val: M::Offset = + wasi_try!(argv_buf_size_val.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem!(argc.write(argc_val)); wasi_try_mem!(argv_buf_size.write(argv_buf_size_val)); @@ -379,8 +382,7 @@ pub fn clock_time_get( ) -> __wasi_errno_t { debug!( "wasi::clock_time_get clock_id: {}, precision: {}", - clock_id, - precision + clock_id, precision ); let memory = thread.memory(); @@ -437,7 +439,8 @@ pub fn environ_sizes_get( let environ_count = environ_count.deref(memory); let environ_buf_size = environ_buf_size.deref(memory); - let env_var_count: M::Offset = wasi_try!(state.envs.len().try_into().map_err(|_| __WASI_EOVERFLOW)); + let env_var_count: M::Offset = + wasi_try!(state.envs.len().try_into().map_err(|_| __WASI_EOVERFLOW)); let env_buf_size: usize = state.envs.iter().map(|v| v.len() + 1).sum(); let env_buf_size: M::Offset = wasi_try!(env_buf_size.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem!(environ_count.write(env_var_count)); @@ -588,7 +591,7 @@ pub fn fd_fdstat_get( ); let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); let stat = wasi_try!(state.fs.fdstat(inodes.deref(), fd)); - + wasi_try_mem!(buf_ptr.write(memory, stat)); __WASI_ESUCCESS @@ -853,20 +856,12 @@ pub fn fd_pread( } } Kind::Socket { socket } => { - wasi_try_ok!( - socket.recv(memory, iovs), - thread - ) + wasi_try_ok!(socket.recv(memory, iovs), thread) } Kind::Pipe { pipe } => { - wasi_try_ok!( - pipe.recv(memory, iovs), - thread - ) - } - Kind::EventNotifications { .. } => { - return Ok(__WASI_EINVAL) + wasi_try_ok!(pipe.recv(memory, iovs), thread) } + Kind::EventNotifications { .. } => return Ok(__WASI_EINVAL), Kind::Dir { .. } | Kind::Root { .. } => return Ok(__WASI_EISDIR), Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"), Kind::Buffer { buffer } => { @@ -944,7 +939,12 @@ pub fn fd_prestat_dir_name( __WASI_EOVERFLOW } } - Kind::Symlink { .. } | Kind::Buffer { .. } | Kind::File { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => __WASI_ENOTDIR, + Kind::Symlink { .. } + | Kind::Buffer { .. } + | Kind::File { .. } + | Kind::Socket { .. } + | Kind::Pipe { .. } + | Kind::EventNotifications { .. } => __WASI_ENOTDIR, } } @@ -1031,24 +1031,16 @@ pub fn fd_pwrite( } } Kind::Socket { socket } => { - wasi_try_ok!( - socket.send(memory, iovs_arr), - thread - ) + wasi_try_ok!(socket.send(memory, iovs_arr), thread) } Kind::Pipe { pipe } => { - wasi_try_ok!( - pipe.send(memory, iovs_arr), - thread - ) + wasi_try_ok!(pipe.send(memory, iovs_arr), thread) } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify return Ok(__WASI_EISDIR); } - Kind::EventNotifications { .. } => { - return Ok(__WASI_EINVAL) - } + Kind::EventNotifications { .. } => return Ok(__WASI_EINVAL), Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pwrite"), Kind::Buffer { buffer } => { wasi_try_ok!( @@ -1060,7 +1052,8 @@ pub fn fd_pwrite( } }; - let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); + let bytes_written: M::Offset = + wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(nwritten_ref.write(bytes_written)); Ok(__WASI_ESUCCESS) @@ -1078,7 +1071,7 @@ pub fn fd_pwrite( /// Output: /// - `u32 *nread` /// Number of bytes read -/// +/// pub fn fd_read( thread: &WasiThread, fd: __wasi_fd_t, @@ -1136,22 +1129,20 @@ pub fn fd_read( } } Kind::Socket { socket } => { - wasi_try_ok!( - socket.recv(memory, iovs_arr), - thread - ) + wasi_try_ok!(socket.recv(memory, iovs_arr), thread) } Kind::Pipe { pipe } => { - wasi_try_ok!( - pipe.recv(memory, iovs_arr), - thread - ) + wasi_try_ok!(pipe.recv(memory, iovs_arr), thread) } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify return Ok(__WASI_EISDIR); } - Kind::EventNotifications { counter, is_semaphore, wakers } => { + Kind::EventNotifications { + counter, + is_semaphore, + wakers, + } => { let counter = Arc::clone(counter); let is_semaphore: bool = *is_semaphore; let wakers = Arc::clone(wakers); @@ -1169,9 +1160,20 @@ pub fn fd_read( let val = counter.load(Ordering::Acquire); if val > 0 { let new_val = if is_semaphore { val - 1 } else { 0 }; - if counter.compare_exchange(val, new_val, Ordering::AcqRel, Ordering::Acquire).is_ok() { + if counter + .compare_exchange( + val, + new_val, + Ordering::AcqRel, + Ordering::Acquire, + ) + .is_ok() + { let reader = val.to_ne_bytes(); - ret = wasi_try_ok!(read_bytes(&reader[..], memory, iovs_arr), thread); + ret = wasi_try_ok!( + read_bytes(&reader[..], memory, iovs_arr), + thread + ); break; } else { continue; @@ -1189,7 +1191,7 @@ pub fn fd_read( thread.sleep(Duration::from_millis(5))?; } } - ret + ret } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"), Kind::Buffer { buffer } => { @@ -1202,7 +1204,7 @@ pub fn fd_read( let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); fd_entry.offset += bytes_read as u64; - + bytes_read } }; @@ -1302,9 +1304,12 @@ pub fn fd_readdir( }) .collect() } - Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { - return __WASI_ENOTDIR - } + Kind::File { .. } + | Kind::Symlink { .. } + | Kind::Buffer { .. } + | Kind::Socket { .. } + | Kind::Pipe { .. } + | Kind::EventNotifications { .. } => return __WASI_ENOTDIR, } }; @@ -1331,10 +1336,7 @@ pub fn fd_readdir( if upper_limit != std::mem::size_of::<__wasi_dirent_t>() { break; } - let upper_limit = std::cmp::min( - (buf_len - buf_idx as u64) as usize, - namlen - ); + let upper_limit = std::cmp::min((buf_len - buf_idx as u64) as usize, namlen); for (i, b) in entry_path_str.bytes().take(upper_limit).enumerate() { wasi_try_mem!(buf_arr.index((i + buf_idx) as u64).write(b)); } @@ -1392,9 +1394,7 @@ pub fn fd_dup( let (memory, state) = thread.get_memory_and_wasi_state(0); let fd = wasi_try!(state.fs.clone_fd(fd)); - wasi_try_mem!( - ret_fd.write(memory, fd) - ); + wasi_try_mem!(ret_fd.write(memory, fd)); __WASI_ESUCCESS } @@ -1421,15 +1421,10 @@ pub fn fd_event( inodes.deref_mut(), kind, false, - "event".to_string() - ); - let rights = __WASI_RIGHT_FD_READ | - __WASI_RIGHT_FD_WRITE | - __WASI_RIGHT_POLL_FD_READWRITE; - let fd = wasi_try!( - state.fs - .create_fd(rights, rights, 0, 0, inode) + "event".to_string(), ); + let rights = __WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_POLL_FD_READWRITE; + let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); wasi_try_mem!(ret_fd.write(memory, fd)); @@ -1493,7 +1488,11 @@ pub fn fd_seek( Kind::Symlink { .. } => { unimplemented!("wasi::fd_seek not implemented for symlinks") } - Kind::Dir { .. } | Kind::Root { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { + Kind::Dir { .. } + | Kind::Root { .. } + | Kind::Socket { .. } + | Kind::Pipe { .. } + | Kind::EventNotifications { .. } => { // TODO: check this return Ok(__WASI_EINVAL); } @@ -1549,7 +1548,11 @@ pub fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { } } Kind::Root { .. } | Kind::Dir { .. } => return __WASI_EISDIR, - Kind::Buffer { .. } | Kind::Symlink { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => return __WASI_EINVAL, + Kind::Buffer { .. } + | Kind::Symlink { .. } + | Kind::Socket { .. } + | Kind::Pipe { .. } + | Kind::EventNotifications { .. } => return __WASI_EINVAL, } } @@ -1665,22 +1668,18 @@ pub fn fd_write( } } Kind::Socket { socket } => { - wasi_try_ok!( - socket.send(memory, iovs_arr), - thread - ) + wasi_try_ok!(socket.send(memory, iovs_arr), thread) } Kind::Pipe { pipe } => { - wasi_try_ok!( - pipe.send(memory, iovs_arr), - thread - ) + wasi_try_ok!(pipe.send(memory, iovs_arr), thread) } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify return Ok(__WASI_EISDIR); } - Kind::EventNotifications { counter, wakers, .. } => { + Kind::EventNotifications { + counter, wakers, .. + } => { let mut val = 0u64.to_ne_bytes(); let written = wasi_try_ok!(write_bytes(&mut val[..], memory, iovs_arr)); if written != val.len() { @@ -1719,7 +1718,8 @@ pub fn fd_write( } }; - let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); + let bytes_written: M::Offset = + wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(nwritten_ref.write(bytes_written)); Ok(__WASI_ESUCCESS) @@ -1740,31 +1740,25 @@ pub fn fd_pipe( trace!("wasi::fd_pipe"); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); - + let (pipe1, pipe2) = WasiPipe::new(); - + let inode1 = state.fs.create_inode_with_default_stat( inodes.deref_mut(), Kind::Pipe { pipe: pipe1 }, false, - "pipe".to_string() + "pipe".to_string(), ); let inode2 = state.fs.create_inode_with_default_stat( inodes.deref_mut(), Kind::Pipe { pipe: pipe2 }, false, - "pipe".to_string() + "pipe".to_string(), ); - + let rights = super::state::all_socket_rights(); - let fd1 = wasi_try!( - state.fs - .create_fd(rights, rights, 0, 0, inode1) - ); - let fd2 = wasi_try!( - state.fs - .create_fd(rights, rights, 0, 0, inode2) - ); + let fd1 = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode1)); + let fd2 = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode2)); wasi_try_mem!(ro_fd1.write(memory, fd1)); wasi_try_mem!(ro_fd2.write(memory, fd2)); @@ -2139,9 +2133,12 @@ pub fn path_link( entries.insert(new_entry_name, source_inode); } Kind::Root { .. } => return __WASI_EINVAL, - Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { - return __WASI_ENOTDIR - } + Kind::File { .. } + | Kind::Symlink { .. } + | Kind::Buffer { .. } + | Kind::Socket { .. } + | Kind::Pipe { .. } + | Kind::EventNotifications { .. } => return __WASI_ENOTDIR, } } inodes.arena[source_inode].stat.write().unwrap().st_nlink += 1; @@ -2285,7 +2282,11 @@ pub fn path_open( .map_err(fs_error_into_wasi_err))); } Kind::Buffer { .. } => unimplemented!("wasi::path_open for Buffer type files"), - Kind::Dir { .. } | Kind::Root { .. } | Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => {} + Kind::Dir { .. } + | Kind::Root { .. } + | Kind::Socket { .. } + | Kind::Pipe { .. } + | Kind::EventNotifications { .. } => {} Kind::Symlink { base_po_dir, path_to_symlink, @@ -2448,7 +2449,8 @@ pub fn path_readlink( wasi_try_mem!(out.write_slice(&bytes[..])); // should we null terminate this? - let bytes_len: M::Offset = wasi_try!(bytes.len().try_into().map_err(|_| __WASI_EOVERFLOW)); + let bytes_len: M::Offset = + wasi_try!(bytes.len().try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem!(buf_used.deref(memory).write(bytes_len)); } else { return __WASI_EINVAL; @@ -2595,7 +2597,9 @@ pub fn path_rename( out_path } Kind::Root { .. } => return __WASI_ENOTCAPABLE, - Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => return __WASI_EINVAL, + Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { + return __WASI_EINVAL + } Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => { unreachable!("Fatal internal logic error: parent of inode is not a directory") } @@ -2609,7 +2613,9 @@ pub fn path_rename( wasi_try!(entries.remove(&source_entry_name).ok_or(__WASI_ENOENT)) } Kind::Root { .. } => return __WASI_ENOTCAPABLE, - Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => return __WASI_EINVAL, + Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { + return __WASI_EINVAL + } Kind::Symlink { .. } | Kind::File { .. } | Kind::Buffer { .. } => { unreachable!("Fatal internal logic error: parent of inode is not a directory") } @@ -2746,7 +2752,9 @@ pub fn path_symlink( } } Kind::Root { .. } => return __WASI_ENOTCAPABLE, - Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => return __WASI_EINVAL, + Kind::Socket { .. } | Kind::Pipe { .. } | Kind::EventNotifications { .. } => { + return __WASI_EINVAL + } Kind::File { .. } | Kind::Symlink { .. } | Kind::Buffer { .. } => { unreachable!("get_parent_inode_at_path returned something other than a Dir or Root") } @@ -2933,7 +2941,7 @@ pub fn poll_oneoff( for sub in subscription_array.iter() { let s: WasiSubscription = wasi_try_ok!(wasi_try_mem_ok!(sub.read()).try_into()); let mut peb = PollEventBuilder::new(); - + let fd = match s.event_type { EventType::Read(__wasi_subscription_fs_readwrite_t { fd }) => { match fd { @@ -3054,24 +3062,23 @@ pub fn poll_oneoff( let now = platform_clock_time_get(__WASI_CLOCK_MONOTONIC, 1_000_000).unwrap() as u128; let delta = match now.checked_sub(start) { Some(a) => Duration::from_nanos(a as u64), - None => Duration::ZERO + None => Duration::ZERO, }; match poll( fds.as_slice(), in_events.as_slice(), seen_events.as_mut_slice(), Duration::from_millis(1), - ) - { + ) { Ok(0) => { thread.yield_now()?; - }, + } Ok(a) => { triggered = a; - }, + } Err(FsError::WouldBlock) => { thread.sleep(Duration::from_millis(1))?; - }, + } Err(err) => { return Ok(fs_error_into_wasi_err(err)); } @@ -3129,7 +3136,7 @@ pub fn poll_oneoff( wasi_try_mem_ok!(event_array.index(events_seen as u64).write(event)); events_seen += 1; } - if triggered <= 0 { + if triggered == 0 { for (clock_info, userdata) in clock_subs { let event = __wasi_event_t { userdata, @@ -3194,7 +3201,7 @@ pub fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { pub fn random_get( thread: &WasiThread, buf: WasmPtr, - buf_len: M::Offset + buf_len: M::Offset, ) -> __wasi_errno_t { trace!("wasi::random_get buf_len: {}", buf_len); let memory = thread.memory(); @@ -3260,7 +3267,7 @@ pub fn tty_set( tty_state: WasmPtr<__wasi_tty_t, M>, ) -> __wasi_errno_t { debug!("wasi::tty_stdout"); - + let memory = thread.memory(); let state = wasi_try_mem!(tty_state.read(memory)); let state = super::runtime::WasiTtyState { @@ -3271,27 +3278,27 @@ pub fn tty_set( stdin_tty: match state.stdin_tty { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }, stdout_tty: match state.stdout_tty { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }, stderr_tty: match state.stderr_tty { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }, echo: match state.echo { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }, line_buffered: match state.line_buffered { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }, }; @@ -3312,9 +3319,7 @@ pub fn getcwd( debug!("wasi::getpwd"); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); - let (_, cur_dir) = wasi_try!(state.fs.get_current_dir( - inodes.deref_mut() - )); + let (_, cur_dir) = wasi_try!(state.fs.get_current_dir(inodes.deref_mut())); let cur_dir = cur_dir.as_bytes(); let max_path_len = wasi_try_mem!(path_len.read(memory)); @@ -3378,21 +3383,19 @@ pub fn thread_spawn( let reactor = match reactor { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }; - let child = wasi_try!( - thread.env.runtime - .thread_spawn(method.as_str(), user_data, reactor) - .map_err(|err| { - let err: __wasi_errno_t = err.into(); - err - }) - ); + let child = wasi_try!(thread + .env + .runtime + .thread_spawn(method.as_str(), user_data, reactor) + .map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + })); let child: __wasi_tid_t = child.into(); - - wasi_try_mem!( - ret_tid.write(memory, child) - ); + + wasi_try_mem!(ret_tid.write(memory, child)); __WASI_ESUCCESS } @@ -3407,7 +3410,7 @@ pub fn thread_sleep( duration: __wasi_timestamp_t, ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::thread_sleep"); - + let duration = Duration::from_nanos(duration as u64); thread.sleep(duration)?; Ok(__WASI_ESUCCESS) @@ -3423,9 +3426,7 @@ pub fn thread_id( debug!("wasi::thread_id"); let tid: __wasi_tid_t = thread.id.into(); - wasi_try_mem!( - ret_tid.write(thread.memory(), tid) - ); + wasi_try_mem!(ret_tid.write(thread.memory(), tid)); __WASI_ESUCCESS } @@ -3436,21 +3437,14 @@ pub fn thread_id( /// ## Parameters /// /// * `tid` - Handle of the thread to wait on -pub fn thread_join( - thread: &WasiThread, - tid: __wasi_tid_t, -) -> __wasi_errno_t { +pub fn thread_join(thread: &WasiThread, tid: __wasi_tid_t) -> __wasi_errno_t { debug!("wasi::thread_join"); - + let tid: WasiThreadId = tid.into(); - wasi_try!( - thread.env.runtime() - .thread_join(tid) - .map_err(|err| { - let err: __wasi_errno_t = err.into(); - err - }) - ); + wasi_try!(thread.env.runtime().thread_join(tid).map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + })); __WASI_ESUCCESS } @@ -3463,19 +3457,13 @@ pub fn thread_parallelism( ret_parallelism: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::thread_parallelism"); - - let parallelism = wasi_try!( - thread.runtime() - .thread_parallelism() - .map_err(|err| { - let err: __wasi_errno_t = err.into(); - err - }) - ); + + let parallelism = wasi_try!(thread.runtime().thread_parallelism().map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + })); let parallelism: M::Offset = wasi_try!(parallelism.try_into().map_err(|_| __WASI_EOVERFLOW)); - wasi_try_mem!( - ret_parallelism.write(thread.memory(), parallelism) - ); + wasi_try_mem!(ret_parallelism.write(thread.memory(), parallelism)); __WASI_ESUCCESS } @@ -3489,9 +3477,7 @@ pub fn getpid( let pid = thread.runtime().getpid(); if let Some(pid) = pid { - wasi_try_mem!( - ret_pid.write(thread.memory(), pid as __wasi_pid_t) - ); + wasi_try_mem!(ret_pid.write(thread.memory(), pid as __wasi_pid_t)); __WASI_ESUCCESS } else { __WASI_ENOTSUP @@ -3511,7 +3497,7 @@ pub fn thread_exit( thread: &WasiThread, exitcode: __wasi_exitcode_t, ) -> Result<__wasi_errno_t, WasiError> { - debug!("wasi::thread_exit"); + debug!("wasi::thread_exit"); Err(WasiError::Exit(exitcode)) } @@ -3609,10 +3595,7 @@ pub fn bus_spawn_remote( /// ## Parameters /// /// * `bid` - Handle of the bus process handle to be closed -pub fn bus_close( - thread: &WasiThread, - bid: __wasi_bid_t, -) -> __wasi_errno_t { +pub fn bus_close(thread: &WasiThread, bid: __wasi_bid_t) -> __wasi_errno_t { debug!("wasi::bus_close"); unimplemented!("wasi::bus_close") } @@ -3655,11 +3638,7 @@ pub fn bus_invoke( /// /// * `cid` - Handle of the call to raise a fault on /// * `fault` - Fault to be raised on the bus -pub fn bus_fault( - thread: &WasiThread, - cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __wasi_errno_t { +pub fn bus_fault(thread: &WasiThread, cid: __wasi_cid_t, fault: __bus_errno_t) -> __wasi_errno_t { debug!("wasi::bus_fault"); unimplemented!("wasi::bus_fault") } @@ -3670,10 +3649,7 @@ pub fn bus_fault( /// ## Parameters /// /// * `cid` - Handle of the bus call handle to be dropped -pub fn bus_drop( - thread: &WasiThread, - cid: __wasi_cid_t, -) -> __wasi_errno_t { +pub fn bus_drop(thread: &WasiThread, cid: __wasi_cid_t) -> __wasi_errno_t { debug!("wasi::bus_drop"); unimplemented!("wasi::bus_drop") } @@ -3816,28 +3792,26 @@ pub fn ws_connect( debug!("wasi::ws_connect"); let memory = thread.memory(); let url = unsafe { get_input_str!(memory, url, url_len) }; - - let socket = wasi_try!( - thread.net().ws_connect(url.as_str()).map_err(net_error_into_wasi_err) - ); + + let socket = wasi_try!(thread + .net() + .ws_connect(url.as_str()) + .map_err(net_error_into_wasi_err)); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); let kind = Kind::Socket { - socket: InodeSocket::new(InodeSocketKind::WebSocket(socket)) + socket: InodeSocket::new(InodeSocketKind::WebSocket(socket)), }; let inode = state.fs.create_inode_with_default_stat( inodes.deref_mut(), kind, false, - "socket".to_string() + "socket".to_string(), ); let rights = super::state::all_socket_rights(); - let fd = wasi_try!( - state.fs - .create_fd(rights, rights, 0, 0, inode) - ); + let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); wasi_try_mem!(ret_sock.write(memory, fd)); @@ -3880,50 +3854,73 @@ pub fn http_request( let gzip = match gzip { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }; - - let socket = wasi_try!( - thread.net() - .http_request(url.as_str(), method.as_str(), headers.as_str(), gzip) - .map_err(net_error_into_wasi_err) - ); + + let socket = wasi_try!(thread + .net() + .http_request(url.as_str(), method.as_str(), headers.as_str(), gzip) + .map_err(net_error_into_wasi_err)); let socket_req = SocketHttpRequest { request: socket.request, response: None, headers: None, - status: socket.status.clone() + status: socket.status.clone(), }; let socket_res = SocketHttpRequest { request: None, response: socket.response, headers: None, - status: socket.status.clone() + status: socket.status.clone(), }; let socket_hdr = SocketHttpRequest { request: None, response: None, headers: socket.headers, - status: socket.status.clone() + status: socket.status.clone(), }; let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); let kind_req = Kind::Socket { - socket: InodeSocket::new(InodeSocketKind::HttpRequest(Mutex::new(socket_req), InodeHttpSocketType::Request)) + socket: InodeSocket::new(InodeSocketKind::HttpRequest( + Mutex::new(socket_req), + InodeHttpSocketType::Request, + )), }; let kind_res = Kind::Socket { - socket: InodeSocket::new(InodeSocketKind::HttpRequest(Mutex::new(socket_res), InodeHttpSocketType::Response)) + socket: InodeSocket::new(InodeSocketKind::HttpRequest( + Mutex::new(socket_res), + InodeHttpSocketType::Response, + )), }; let kind_hdr = Kind::Socket { - socket: InodeSocket::new(InodeSocketKind::HttpRequest(Mutex::new(socket_hdr), InodeHttpSocketType::Headers)) + socket: InodeSocket::new(InodeSocketKind::HttpRequest( + Mutex::new(socket_hdr), + InodeHttpSocketType::Headers, + )), }; - let inode_req = state.fs.create_inode_with_default_stat(inodes.deref_mut(), kind_req, false, "http_request".to_string()); - let inode_res = state.fs.create_inode_with_default_stat(inodes.deref_mut(), kind_res, false, "http_response".to_string()); - let inode_hdr = state.fs.create_inode_with_default_stat(inodes.deref_mut(), kind_hdr, false, "http_headers".to_string()); + let inode_req = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + kind_req, + false, + "http_request".to_string(), + ); + let inode_res = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + kind_res, + false, + "http_response".to_string(), + ); + let inode_hdr = state.fs.create_inode_with_default_stat( + inodes.deref_mut(), + kind_hdr, + false, + "http_headers".to_string(), + ); let rights = super::state::all_socket_rights(); - + let handles = __wasi_http_handles_t { req: wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode_req)), res: wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode_res)), @@ -3952,24 +3949,22 @@ pub fn http_status( let memory = thread.memory(); let ref_status = status.deref(memory); - - let http_status = wasi_try!( - __sock_actor(thread, sock, 0, |socket| { - socket.http_status() - }) - ); + + let http_status = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + socket.http_status() + })); // Write everything else and return the status to the caller let status = __wasi_http_status_t { ok: __WASI_BOOL_TRUE, redirect: match http_status.redirected { true => __WASI_BOOL_TRUE, - false => __WASI_BOOL_FALSE + false => __WASI_BOOL_FALSE, }, size: wasi_try!(http_status.size.try_into().map_err(|_| __WASI_EOVERFLOW)), - status: http_status.status + status: http_status.status, }; - + wasi_try_mem!(ref_status.write(status)); __WASI_ESUCCESS @@ -4000,36 +3995,29 @@ pub fn port_bridge( __WASI_STREAM_SECURITY_ANY_ENCRYPTION => StreamSecurity::AnyEncyption, __WASI_STREAM_SECURITY_CLASSIC_ENCRYPTION => StreamSecurity::ClassicEncryption, __WASI_STREAM_SECURITY_DOUBLE_ENCRYPTION => StreamSecurity::DoubleEncryption, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }; - - wasi_try!( - thread.net().bridge(network.as_str(), token.as_str(), security).map_err(net_error_into_wasi_err) - ); + + wasi_try!(thread + .net() + .bridge(network.as_str(), token.as_str(), security) + .map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_unbridge()` /// Disconnects from a remote network -pub fn port_unbridge( - thread: &WasiThread, -) -> __wasi_errno_t { +pub fn port_unbridge(thread: &WasiThread) -> __wasi_errno_t { debug!("wasi::port_unbridge"); - wasi_try!( - thread.net().unbridge().map_err(net_error_into_wasi_err) - ); + wasi_try!(thread.net().unbridge().map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_dhcp_acquire()` /// Acquires a set of IP addresses using DHCP -pub fn port_dhcp_acquire( - thread: &WasiThread, -) -> __wasi_errno_t { +pub fn port_dhcp_acquire(thread: &WasiThread) -> __wasi_errno_t { debug!("wasi::port_dhcp_acquire"); - wasi_try!( - thread.net().dhcp_acquire().map_err(net_error_into_wasi_err) - ); + wasi_try!(thread.net().dhcp_acquire().map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } @@ -4046,9 +4034,10 @@ pub fn port_addr_add( debug!("wasi::port_addr_add"); let memory = thread.memory(); let cidr = wasi_try!(super::state::read_cidr(memory, ip)); - wasi_try!( - thread.net().ip_add(cidr.ip, cidr.prefix).map_err(net_error_into_wasi_err) - ); + wasi_try!(thread + .net() + .ip_add(cidr.ip, cidr.prefix) + .map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } @@ -4065,21 +4054,15 @@ pub fn port_addr_remove( debug!("wasi::port_addr_remove"); let memory = thread.memory(); let ip = wasi_try!(super::state::read_ip(memory, ip)); - wasi_try!( - thread.net().ip_remove(ip).map_err(net_error_into_wasi_err) - ); + wasi_try!(thread.net().ip_remove(ip).map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_addr_clear()` /// Clears all the addresses on the local port -pub fn port_addr_clear( - thread: &WasiThread, -) -> __wasi_errno_t { +pub fn port_addr_clear(thread: &WasiThread) -> __wasi_errno_t { debug!("wasi::port_addr_clear"); - wasi_try!( - thread.net().ip_clear().map_err(net_error_into_wasi_err) - ); + wasi_try!(thread.net().ip_clear().map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } @@ -4091,15 +4074,9 @@ pub fn port_mac( ) -> __wasi_errno_t { debug!("wasi::port_mac"); let memory = thread.memory(); - let mac = wasi_try!( - thread.net().mac().map_err(net_error_into_wasi_err) - ); - let mac = __wasi_hardwareaddress_t { - octs: mac - }; - wasi_try_mem!( - ret_mac.write(memory, mac) - ); + let mac = wasi_try!(thread.net().mac().map_err(net_error_into_wasi_err)); + let mac = __wasi_hardwareaddress_t { octs: mac }; + wasi_try_mem!(ret_mac.write(memory, mac)); __WASI_ESUCCESS } @@ -4125,13 +4102,10 @@ pub fn port_addr_list( let memory = thread.memory(); let max_addrs = wasi_try_mem!(naddrs.read(memory)); let max_addrs: u64 = wasi_try!(max_addrs.try_into().map_err(|_| __WASI_EOVERFLOW)); - let ref_addrs = wasi_try_mem!(addrs.slice(memory, wasi_try!(to_offset::(max_addrs as usize)))); - - let addrs = wasi_try!( - thread.net() - .ip_list() - .map_err(net_error_into_wasi_err) - ); + let ref_addrs = + wasi_try_mem!(addrs.slice(memory, wasi_try!(to_offset::(max_addrs as usize)))); + + let addrs = wasi_try!(thread.net().ip_list().map_err(net_error_into_wasi_err)); let addrs_len: M::Offset = wasi_try!(addrs.len().try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem!(naddrs.write(memory, addrs_len)); @@ -4161,9 +4135,10 @@ pub fn port_gateway_set( let memory = thread.memory(); let ip = wasi_try!(super::state::read_ip(memory, ip)); - wasi_try!( - thread.net().gateway_set(ip).map_err(net_error_into_wasi_err) - ); + wasi_try!(thread + .net() + .gateway_set(ip) + .map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } @@ -4183,23 +4158,20 @@ pub fn port_route_add( let preferred_until = wasi_try_mem!(preferred_until.read(memory)); let preferred_until = match preferred_until.tag { __WASI_OPTION_NONE => None, - __WASI_OPTION_SOME => { - Some(Duration::from_nanos(preferred_until.u)) - }, - _ => return __WASI_EINVAL + __WASI_OPTION_SOME => Some(Duration::from_nanos(preferred_until.u)), + _ => return __WASI_EINVAL, }; let expires_at = wasi_try_mem!(expires_at.read(memory)); let expires_at = match expires_at.tag { __WASI_OPTION_NONE => None, - __WASI_OPTION_SOME => { - Some(Duration::from_nanos(expires_at.u)) - }, - _ => return __WASI_EINVAL + __WASI_OPTION_SOME => Some(Duration::from_nanos(expires_at.u)), + _ => return __WASI_EINVAL, }; - wasi_try!( - thread.net().route_add(cidr, via_router, preferred_until, expires_at).map_err(net_error_into_wasi_err) - ); + wasi_try!(thread + .net() + .route_add(cidr, via_router, preferred_until, expires_at) + .map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } @@ -4212,21 +4184,18 @@ pub fn port_route_remove( debug!("wasi::port_route_remove"); let memory = thread.memory(); let ip = wasi_try!(super::state::read_ip(memory, ip)); - wasi_try!( - thread.net().route_remove(ip).map_err(net_error_into_wasi_err) - ); + wasi_try!(thread + .net() + .route_remove(ip) + .map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_route_clear()` /// Clears all the routes in the local port -pub fn port_route_clear( - thread: &WasiThread, -) -> __wasi_errno_t { +pub fn port_route_clear(thread: &WasiThread) -> __wasi_errno_t { debug!("wasi::port_route_clear"); - wasi_try!( - thread.net().route_clear().map_err(net_error_into_wasi_err) - ); + wasi_try!(thread.net().route_clear().map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } @@ -4247,12 +4216,12 @@ pub fn port_route_list( debug!("wasi::port_route_list"); let memory = thread.memory(); let nroutes = nroutes.deref(memory); - let max_routes: usize = wasi_try!(wasi_try_mem!(nroutes.read()).try_into().map_err(|_| __WASI_EINVAL)); + let max_routes: usize = wasi_try!(wasi_try_mem!(nroutes.read()) + .try_into() + .map_err(|_| __WASI_EINVAL)); let ref_routes = wasi_try_mem!(routes.slice(memory, wasi_try!(to_offset::(max_routes)))); - - let routes = wasi_try!( - thread.net().route_list().map_err(net_error_into_wasi_err) - ); + + let routes = wasi_try!(thread.net().route_list().map_err(net_error_into_wasi_err)); let routes_len: M::Offset = wasi_try!(routes.len().try_into().map_err(|_| __WASI_EINVAL)); wasi_try_mem!(nroutes.write(routes_len)); @@ -4287,12 +4256,15 @@ pub fn sock_shutdown( __WASI_SHUT_RD => std::net::Shutdown::Read, __WASI_SHUT_WR => std::net::Shutdown::Write, a if a == both => std::net::Shutdown::Both, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }; - wasi_try!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_SHUTDOWN, |socket| { - socket.shutdown(how) - })); + wasi_try!(__sock_actor_mut( + thread, + sock, + __WASI_RIGHT_SOCK_SHUTDOWN, + |socket| { socket.shutdown(how) } + )); __WASI_ESUCCESS } @@ -4302,15 +4274,11 @@ pub fn sock_shutdown( pub fn sock_status( thread: &WasiThread, sock: __wasi_fd_t, - ret_status: WasmPtr<__wasi_sockstatus_t, M> + ret_status: WasmPtr<__wasi_sockstatus_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_status"); - - let status = wasi_try!( - __sock_actor(thread, sock, 0, |socket| { - socket.status() - }) - ); + + let status = wasi_try!(__sock_actor(thread, sock, 0, |socket| { socket.status() })); use super::state::WasiSocketStatus; let status = match status { @@ -4321,7 +4289,7 @@ pub fn sock_status( }; wasi_try_mem!(ret_status.write(thread.memory(), status)); - + __WASI_ESUCCESS } @@ -4342,15 +4310,16 @@ pub fn sock_addr_local( ret_addr: WasmPtr<__wasi_addr_port_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_addr_local"); - - let addr = wasi_try!( - __sock_actor(thread, sock, 0, |socket| { - socket.addr_local() - }) - ); - wasi_try!( - super::state::write_ip_port(thread.memory(), ret_addr, addr.ip(), addr.port()) - ); + + let addr = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + socket.addr_local() + })); + wasi_try!(super::state::write_ip_port( + thread.memory(), + ret_addr, + addr.ip(), + addr.port() + )); __WASI_ESUCCESS } @@ -4372,14 +4341,15 @@ pub fn sock_addr_peer( ) -> __wasi_errno_t { debug!("wasi::sock_addr_peer"); - let addr = wasi_try!( - __sock_actor(thread, sock, 0, |socket| { - socket.addr_peer() - }) - ); - wasi_try!( - super::state::write_ip_port(thread.memory(), ro_addr, addr.ip(), addr.port()) - ); + let addr = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + socket.addr_peer() + })); + wasi_try!(super::state::write_ip_port( + thread.memory(), + ro_addr, + addr.ip(), + addr.port() + )); __WASI_ESUCCESS } @@ -4412,27 +4382,24 @@ pub fn sock_open( debug!("wasi::sock_open"); let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); - + let kind = match ty { - __WASI_SOCK_TYPE_STREAM | - __WASI_SOCK_TYPE_DGRAM => { - Kind::Socket { - socket: InodeSocket::new(InodeSocketKind::PreSocket { - family: af, - ty, - pt, - addr: None, - only_v6: false, - reuse_port: false, - reuse_addr: false, - send_buf_size: None, - recv_buf_size: None, - send_timeout: None, - recv_timeout: None, - connect_timeout: None, - accept_timeout: None, - }) - } + __WASI_SOCK_TYPE_STREAM | __WASI_SOCK_TYPE_DGRAM => Kind::Socket { + socket: InodeSocket::new(InodeSocketKind::PreSocket { + family: af, + ty, + pt, + addr: None, + only_v6: false, + reuse_port: false, + reuse_addr: false, + send_buf_size: None, + recv_buf_size: None, + send_timeout: None, + recv_timeout: None, + connect_timeout: None, + accept_timeout: None, + }), }, _ => return __WASI_ENOTSUP, }; @@ -4441,13 +4408,10 @@ pub fn sock_open( inodes.deref_mut(), kind, false, - "socket".to_string() + "socket".to_string(), ); let rights = super::state::all_socket_rights(); - let fd = wasi_try!( - state.fs - .create_fd(rights, rights, 0, 0, inode) - ); + let fd = wasi_try!(state.fs.create_fd(rights, rights, 0, 0, inode)); wasi_try_mem!(ro_sock.write(memory, fd)); @@ -4478,11 +4442,9 @@ pub fn sock_set_opt_flag( }; let option: super::state::WasiSocketOption = opt.into(); - wasi_try!( - __sock_actor_mut(thread, sock, 0, |socket| { - socket.set_opt_flag(option, flag) - }) - ); + wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + socket.set_opt_flag(option, flag) + })); __WASI_ESUCCESS } @@ -4504,18 +4466,16 @@ pub fn sock_get_opt_flag( let memory = thread.memory(); let option: super::state::WasiSocketOption = opt.into(); - let flag = wasi_try!( - __sock_actor(thread, sock, 0, |socket| { - socket.get_opt_flag(option) - }) - ); + let flag = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + socket.get_opt_flag(option) + })); let flag = match flag { false => __WASI_BOOL_FALSE, - true => __WASI_BOOL_TRUE + true => __WASI_BOOL_TRUE, }; wasi_try_mem!(ret_flag.write(memory, flag)); - + __WASI_ESUCCESS } @@ -4539,10 +4499,8 @@ pub fn sock_set_opt_time( let time = wasi_try_mem!(time.read(memory)); let time = match time.tag { __WASI_OPTION_NONE => None, - __WASI_OPTION_SOME => { - Some(Duration::from_nanos(time.u)) - }, - _ => return __WASI_EINVAL + __WASI_OPTION_SOME => Some(Duration::from_nanos(time.u)), + _ => return __WASI_EINVAL, }; let ty = match opt { @@ -4551,15 +4509,13 @@ pub fn sock_set_opt_time( __WASI_SOCK_OPTION_CONNECT_TIMEOUT => wasmer_vnet::TimeType::ConnectTimeout, __WASI_SOCK_OPTION_ACCEPT_TIMEOUT => wasmer_vnet::TimeType::AcceptTimeout, __WASI_SOCK_OPTION_LINGER => wasmer_vnet::TimeType::Linger, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }; let option: super::state::WasiSocketOption = opt.into(); - wasi_try!( - __sock_actor_mut(thread, sock, 0, |socket| { - socket.set_opt_time(ty, time) - }) - ); + wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + socket.set_opt_time(ty, time) + })); __WASI_ESUCCESS } @@ -4585,27 +4541,25 @@ pub fn sock_get_opt_time( __WASI_SOCK_OPTION_CONNECT_TIMEOUT => wasmer_vnet::TimeType::ConnectTimeout, __WASI_SOCK_OPTION_ACCEPT_TIMEOUT => wasmer_vnet::TimeType::AcceptTimeout, __WASI_SOCK_OPTION_LINGER => wasmer_vnet::TimeType::Linger, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }; - let time = wasi_try!( - __sock_actor(thread, sock, 0, |socket| { - socket.opt_time(ty) - }) - ); + let time = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + socket.opt_time(ty) + })); let time = match time { None => __wasi_option_timestamp_t { tag: __WASI_OPTION_NONE, - u: 0 + u: 0, }, Some(timeout) => __wasi_option_timestamp_t { tag: __WASI_OPTION_SOME, - u: timeout.as_nanos() as __wasi_timestamp_t + u: timeout.as_nanos() as __wasi_timestamp_t, }, }; - + wasi_try_mem!(ret_time.write(memory, time)); - + __WASI_ESUCCESS } @@ -4632,29 +4586,19 @@ pub fn sock_set_opt_size( __WASI_SOCK_OPTION_CONNECT_TIMEOUT => wasmer_vnet::TimeType::ConnectTimeout, __WASI_SOCK_OPTION_ACCEPT_TIMEOUT => wasmer_vnet::TimeType::AcceptTimeout, __WASI_SOCK_OPTION_LINGER => wasmer_vnet::TimeType::Linger, - _ => return __WASI_EINVAL + _ => return __WASI_EINVAL, }; let option: super::state::WasiSocketOption = opt.into(); - wasi_try!( - __sock_actor_mut(thread, sock, 0, |socket| { - match opt { - __WASI_SOCK_OPTION_RECV_BUF_SIZE => { - socket.set_recv_buf_size(size as usize) - }, - __WASI_SOCK_OPTION_SEND_BUF_SIZE => { - socket.set_send_buf_size(size as usize) - }, - __WASI_SOCK_OPTION_TTL => { - socket.set_ttl(size as u32) - }, - __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => { - socket.set_multicast_ttl_v4(size as u32) - }, - _ => Err(__WASI_EINVAL) - } - }) - ); + wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + match opt { + __WASI_SOCK_OPTION_RECV_BUF_SIZE => socket.set_recv_buf_size(size as usize), + __WASI_SOCK_OPTION_SEND_BUF_SIZE => socket.set_send_buf_size(size as usize), + __WASI_SOCK_OPTION_TTL => socket.set_ttl(size as u32), + __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => socket.set_multicast_ttl_v4(size as u32), + _ => Err(__WASI_EINVAL), + } + })); __WASI_ESUCCESS } @@ -4675,27 +4619,23 @@ pub fn sock_get_opt_size( debug!("wasi::sock_get_opt_size(ty={})", opt); let memory = thread.memory(); - let size = wasi_try!( - __sock_actor(thread, sock, 0, |socket| { - match opt { - __WASI_SOCK_OPTION_RECV_BUF_SIZE => { - socket.recv_buf_size().map(|a| a as __wasi_filesize_t) - }, - __WASI_SOCK_OPTION_SEND_BUF_SIZE => { - socket.send_buf_size().map(|a| a as __wasi_filesize_t) - }, - __WASI_SOCK_OPTION_TTL => { - socket.ttl().map(|a| a as __wasi_filesize_t) - }, - __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => { - socket.multicast_ttl_v4().map(|a| a as __wasi_filesize_t) - }, - _ => Err(__WASI_EINVAL) + let size = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + match opt { + __WASI_SOCK_OPTION_RECV_BUF_SIZE => { + socket.recv_buf_size().map(|a| a as __wasi_filesize_t) } - }) - ); + __WASI_SOCK_OPTION_SEND_BUF_SIZE => { + socket.send_buf_size().map(|a| a as __wasi_filesize_t) + } + __WASI_SOCK_OPTION_TTL => socket.ttl().map(|a| a as __wasi_filesize_t), + __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => { + socket.multicast_ttl_v4().map(|a| a as __wasi_filesize_t) + } + _ => Err(__WASI_EINVAL), + } + })); wasi_try_mem!(ret_size.write(memory, size)); - + __WASI_ESUCCESS } @@ -4714,15 +4654,13 @@ pub fn sock_join_multicast_v4( iface: WasmPtr<__wasi_addr_ip4_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_join_multicast_v4"); - + let memory = thread.memory(); let multiaddr = wasi_try!(super::state::read_ip_v4(memory, multiaddr)); let iface = wasi_try!(super::state::read_ip_v4(memory, iface)); - wasi_try!( - __sock_actor_mut(thread, sock, 0, |socket| { - socket.join_multicast_v4(multiaddr, iface) - }) - ); + wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + socket.join_multicast_v4(multiaddr, iface) + })); __WASI_ESUCCESS } @@ -4741,15 +4679,13 @@ pub fn sock_leave_multicast_v4( iface: WasmPtr<__wasi_addr_ip4_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_leave_multicast_v4"); - + let memory = thread.memory(); let multiaddr = wasi_try!(super::state::read_ip_v4(memory, multiaddr)); let iface = wasi_try!(super::state::read_ip_v4(memory, iface)); - wasi_try!( - __sock_actor_mut(thread, sock, 0, |socket| { - socket.leave_multicast_v4(multiaddr, iface) - }) - ); + wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + socket.leave_multicast_v4(multiaddr, iface) + })); __WASI_ESUCCESS } @@ -4768,14 +4704,12 @@ pub fn sock_join_multicast_v6( iface: u32, ) -> __wasi_errno_t { debug!("wasi::sock_join_multicast_v6"); - + let memory = thread.memory(); let multiaddr = wasi_try!(super::state::read_ip_v6(memory, multiaddr)); - wasi_try!( - __sock_actor_mut(thread, sock, 0, |socket| { - socket.join_multicast_v6(multiaddr, iface) - }) - ); + wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + socket.join_multicast_v6(multiaddr, iface) + })); __WASI_ESUCCESS } @@ -4794,14 +4728,12 @@ pub fn sock_leave_multicast_v6( iface: u32, ) -> __wasi_errno_t { debug!("wasi::sock_leave_multicast_v6"); - + let memory = thread.memory(); let multiaddr = wasi_try!(super::state::read_ip_v6(memory, multiaddr)); - wasi_try!( - __sock_actor_mut(thread, sock, 0, |socket| { - socket.leave_multicast_v6(multiaddr, iface) - }) - ); + wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + socket.leave_multicast_v6(multiaddr, iface) + })); __WASI_ESUCCESS } @@ -4822,11 +4754,12 @@ pub fn sock_bind( let addr = wasi_try!(super::state::read_ip_port(thread.memory(), addr)); let addr = SocketAddr::new(addr.0, addr.1); - wasi_try!( - __sock_upgrade(thread, sock, __WASI_RIGHT_SOCK_BIND, |socket| { - socket.bind(thread.net(), addr) - }) - ); + wasi_try!(__sock_upgrade( + thread, + sock, + __WASI_RIGHT_SOCK_BIND, + |socket| { socket.bind(thread.net(), addr) } + )); __WASI_ESUCCESS } @@ -4850,11 +4783,12 @@ pub fn sock_listen( debug!("wasi::sock_listen"); let backlog: usize = wasi_try!(backlog.try_into().map_err(|_| __WASI_EINVAL)); - wasi_try!( - __sock_upgrade(thread, sock, __WASI_RIGHT_SOCK_BIND, |socket| { - socket.listen(thread.net(), backlog) - }) - ); + wasi_try!(__sock_upgrade( + thread, + sock, + __WASI_RIGHT_SOCK_BIND, + |socket| { socket.listen(thread.net(), backlog) } + )); __WASI_ESUCCESS } @@ -4884,26 +4818,22 @@ pub fn sock_accept( let (_, state) = thread.get_memory_and_wasi_state(0); loop { wasi_try_ok!( - match __sock_actor - ( - thread, - sock, - __WASI_RIGHT_SOCK_ACCEPT, - |socket| socket.accept_timeout(fd_flags, Duration::from_millis(5)) - ) { + match __sock_actor(thread, sock, __WASI_RIGHT_SOCK_ACCEPT, |socket| socket + .accept_timeout(fd_flags, Duration::from_millis(5))) + { Ok(a) => { ret = a; break; - }, + } Err(__WASI_ETIMEDOUT) => { thread.yield_now()?; continue; - }, + } Err(__WASI_EAGAIN) => { thread.sleep(Duration::from_millis(5))?; continue; } - Err(err) => Err(err) + Err(err) => Err(err), } ); } @@ -4913,24 +4843,26 @@ pub fn sock_accept( let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); let kind = Kind::Socket { - socket: InodeSocket::new(InodeSocketKind::TcpStream(child)) + socket: InodeSocket::new(InodeSocketKind::TcpStream(child)), }; let inode = state.fs.create_inode_with_default_stat( inodes.deref_mut(), kind, false, - "socket".to_string() + "socket".to_string(), ); let rights = super::state::all_socket_rights(); - let fd = wasi_try_ok!( - state.fs - .create_fd(rights, rights, 0, 0, inode) - ); + let fd = wasi_try_ok!(state.fs.create_fd(rights, rights, 0, 0, inode)); + + wasi_try_mem_ok!(ro_fd.write(memory, fd)); + wasi_try_ok!(super::state::write_ip_port( + memory, + ro_addr, + addr.ip(), + addr.port() + )); - wasi_try_mem_ok!(ro_fd.write(memory, fd)); - wasi_try_ok!(super::state::write_ip_port(memory, ro_addr, addr.ip(), addr.port())); - Ok(__WASI_ESUCCESS) } @@ -4955,11 +4887,12 @@ pub fn sock_connect( let addr = wasi_try!(super::state::read_ip_port(thread.memory(), addr)); let addr = SocketAddr::new(addr.0, addr.1); - wasi_try!( - __sock_upgrade(thread, sock, __WASI_RIGHT_SOCK_CONNECT, |socket| { - socket.connect(thread.net(), addr) - }) - ); + wasi_try!(__sock_upgrade( + thread, + sock, + __WASI_RIGHT_SOCK_CONNECT, + |socket| { socket.connect(thread.net(), addr) } + )); __WASI_ESUCCESS } @@ -4990,9 +4923,12 @@ pub fn sock_recv( let memory = thread.memory(); let iovs_arr = wasi_try_mem_ok!(ri_data.slice(memory, ri_data_len)); - let bytes_read = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_RECV, |socket| { - socket.recv(memory, iovs_arr) - })); + let bytes_read = wasi_try_ok!(__sock_actor_mut( + thread, + sock, + __WASI_RIGHT_SOCK_RECV, + |socket| { socket.recv(memory, iovs_arr) } + )); let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(ro_flags.write(memory, 0)); @@ -5029,9 +4965,12 @@ pub fn sock_recv_from( let memory = thread.memory(); let iovs_arr = wasi_try_mem_ok!(ri_data.slice(memory, ri_data_len)); - let bytes_read = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_RECV_FROM, |socket| { - socket.recv_from(memory, iovs_arr, ro_addr) - })); + let bytes_read = wasi_try_ok!(__sock_actor_mut( + thread, + sock, + __WASI_RIGHT_SOCK_RECV_FROM, + |socket| { socket.recv_from(memory, iovs_arr, ro_addr) } + )); let bytes_read: M::Offset = wasi_try_ok!(bytes_read.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(ro_flags.write(memory, 0)); @@ -5066,11 +5005,15 @@ pub fn sock_send( let memory = thread.memory(); let iovs_arr = wasi_try_mem_ok!(si_data.slice(memory, si_data_len)); - let bytes_written = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_SEND, |socket| { - socket.send(memory, iovs_arr) - })); + let bytes_written = wasi_try_ok!(__sock_actor_mut( + thread, + sock, + __WASI_RIGHT_SOCK_SEND, + |socket| { socket.send(memory, iovs_arr) } + )); - let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); + let bytes_written: M::Offset = + wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(ret_data_len.write(memory, bytes_written)); Ok(__WASI_ESUCCESS) @@ -5100,15 +5043,19 @@ pub fn sock_send_to( ret_data_len: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::sock_send_to"); - + let memory = thread.memory(); let iovs_arr = wasi_try_mem_ok!(si_data.slice(memory, si_data_len)); - let bytes_written = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_SEND_TO, |socket| { - socket.send_to::(memory, iovs_arr, addr) - })); + let bytes_written = wasi_try_ok!(__sock_actor_mut( + thread, + sock, + __WASI_RIGHT_SOCK_SEND_TO, + |socket| { socket.send_to::(memory, iovs_arr, addr) } + )); - let bytes_written: M::Offset = wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); + let bytes_written: M::Offset = + wasi_try_ok!(bytes_written.try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem_ok!(ret_data_len.write(memory, bytes_written as M::Offset)); Ok(__WASI_ESUCCESS) @@ -5223,10 +5170,15 @@ pub unsafe fn sock_send_file( }; // Write it down to the socket - let bytes_written = wasi_try_ok!(__sock_actor_mut(thread, sock, __WASI_RIGHT_SOCK_SEND, |socket| { - let buf = (&buf[..]).to_vec(); - socket.send_bytes::(Bytes::from(buf)) - })); + let bytes_written = wasi_try_ok!(__sock_actor_mut( + thread, + sock, + __WASI_RIGHT_SOCK_SEND, + |socket| { + let buf = (&buf[..]).to_vec(); + socket.send_bytes::(Bytes::from(buf)) + } + )); total_written += bytes_written as u64; } @@ -5269,17 +5221,12 @@ pub fn resolve( let host_str = unsafe { get_input_str!(memory, host, host_len) }; let addrs = wasi_try_mem!(addrs.slice(memory, wasi_try!(to_offset::(naddrs)))); - let port = if port > 0 { - Some(port) - } else { - None - }; - - let found_ips = wasi_try!( - thread.net() - .resolve(host_str.as_str(), port, None) - .map_err(net_error_into_wasi_err) - ); + let port = if port > 0 { Some(port) } else { None }; + + let found_ips = wasi_try!(thread + .net() + .resolve(host_str.as_str(), port, None) + .map_err(net_error_into_wasi_err)); let mut idx = 0; for found_ip in found_ips.iter().take(naddrs) { diff --git a/lib/wasi/src/syscalls/wasi.rs b/lib/wasi/src/syscalls/wasi.rs index 3889961db3f..bed579502fe 100644 --- a/lib/wasi/src/syscalls/wasi.rs +++ b/lib/wasi/src/syscalls/wasi.rs @@ -1,7 +1,7 @@ #![deny(dead_code)] +use crate::{WasiError, WasiState, WasiThread}; +use wasmer::{Memory, Memory32, MemorySize, WasmPtr, WasmSlice}; use wasmer_wasi_types::*; -use wasmer::{Memory, WasmPtr, WasmSlice, MemorySize, Memory32}; -use crate::{WasiThread, WasiState, WasiError}; type MemoryType = Memory32; type MemoryOffset = u32; @@ -193,7 +193,11 @@ pub(crate) fn fd_readdir( super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) } -pub(crate) fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { +pub(crate) fn fd_renumber( + thread: &WasiThread, + from: __wasi_fd_t, + to: __wasi_fd_t, +) -> __wasi_errno_t { super::fd_renumber(thread, from, to) } @@ -259,7 +263,9 @@ pub(crate) fn path_filestat_set_times( st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { - super::path_filestat_set_times::(thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags) + super::path_filestat_set_times::( + thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, + ) } pub(crate) fn path_link( @@ -272,7 +278,16 @@ pub(crate) fn path_link( new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_link::(thread, old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) + super::path_link::( + thread, + old_fd, + old_flags, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len, + ) } pub(crate) fn path_open( @@ -287,7 +302,18 @@ pub(crate) fn path_open( fs_flags: __wasi_fdflags_t, fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::path_open::(thread, dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) + super::path_open::( + thread, + dirfd, + dirflags, + path, + path_len, + o_flags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd, + ) } pub(crate) fn path_readlink( @@ -320,7 +346,15 @@ pub(crate) fn path_rename( new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_rename::(thread, old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) + super::path_rename::( + thread, + old_fd, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len, + ) } pub(crate) fn path_symlink( @@ -364,7 +398,7 @@ pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_er pub(crate) fn random_get( thread: &WasiThread, buf: WasmPtr, - buf_len: MemoryOffset + buf_len: MemoryOffset, ) -> __wasi_errno_t { super::random_get::(thread, buf, buf_len) } @@ -382,7 +416,15 @@ pub(crate) fn sock_recv( ro_data_len: WasmPtr, ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags) + super::sock_recv::( + thread, + sock, + ri_data, + ri_data_len, + ri_flags, + ro_data_len, + ro_flags, + ) } pub(crate) fn sock_send( diff --git a/lib/wasi/src/syscalls/wasix32.rs b/lib/wasi/src/syscalls/wasix32.rs index 1fe15d9beed..30e50560df6 100644 --- a/lib/wasi/src/syscalls/wasix32.rs +++ b/lib/wasi/src/syscalls/wasix32.rs @@ -1,7 +1,7 @@ #![deny(dead_code)] +use crate::{WasiError, WasiState, WasiThread}; +use wasmer::{Memory, Memory32, MemorySize, WasmPtr, WasmSlice}; use wasmer_wasi_types::*; -use wasmer::{Memory, WasmPtr, WasmSlice, MemorySize, Memory32}; -use crate::{WasiThread, WasiState, WasiError}; type MemoryType = Memory32; type MemoryOffset = u32; @@ -193,7 +193,11 @@ pub(crate) fn fd_readdir( super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) } -pub(crate) fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { +pub(crate) fn fd_renumber( + thread: &WasiThread, + from: __wasi_fd_t, + to: __wasi_fd_t, +) -> __wasi_errno_t { super::fd_renumber(thread, from, to) } @@ -259,7 +263,9 @@ pub(crate) fn path_filestat_set_times( st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { - super::path_filestat_set_times::(thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags) + super::path_filestat_set_times::( + thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, + ) } pub(crate) fn path_link( @@ -272,7 +278,16 @@ pub(crate) fn path_link( new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_link::(thread, old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) + super::path_link::( + thread, + old_fd, + old_flags, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len, + ) } pub(crate) fn path_open( @@ -287,7 +302,18 @@ pub(crate) fn path_open( fs_flags: __wasi_fdflags_t, fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::path_open::(thread, dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) + super::path_open::( + thread, + dirfd, + dirflags, + path, + path_len, + o_flags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd, + ) } pub(crate) fn path_readlink( @@ -320,7 +346,15 @@ pub(crate) fn path_rename( new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_rename::(thread, old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) + super::path_rename::( + thread, + old_fd, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len, + ) } pub(crate) fn path_symlink( @@ -364,7 +398,7 @@ pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_er pub(crate) fn random_get( thread: &WasiThread, buf: WasmPtr, - buf_len: MemoryOffset + buf_len: MemoryOffset, ) -> __wasi_errno_t { super::random_get::(thread, buf, buf_len) } @@ -449,10 +483,7 @@ pub(crate) fn thread_id( super::thread_id::(thread, ret_tid) } -pub(crate) fn thread_join( - thread: &WasiThread, - tid: __wasi_tid_t, -) -> __wasi_errno_t { +pub(crate) fn thread_join(thread: &WasiThread, tid: __wasi_tid_t) -> __wasi_errno_t { super::thread_join(thread, tid) } @@ -497,7 +528,22 @@ pub(crate) fn bus_spawn_local( working_dir_len: MemoryOffset, ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, ) -> __wasi_errno_t { - super::bus_spawn_local::(thread, name, name_len, chroot, args, args_len, preopen, preopen_len, stdin, stdout, stderr, working_dir, working_dir_len, ret_handles) + super::bus_spawn_local::( + thread, + name, + name_len, + chroot, + args, + args_len, + preopen, + preopen_len, + stdin, + stdout, + stderr, + working_dir, + working_dir_len, + ret_handles, + ) } pub(crate) fn bus_spawn_remote( @@ -520,13 +566,29 @@ pub(crate) fn bus_spawn_remote( token_len: MemoryOffset, ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, ) -> __wasi_errno_t { - super::bus_spawn_remote::(thread, name, name_len, chroot, args, args_len, preopen, preopen_len, working_dir, working_dir_len, stdin, stdout, stderr, instance, instance_len, token, token_len, ret_handles) -} - -pub(crate) fn bus_close( - thread: &WasiThread, - bid: __wasi_bid_t, -) -> __wasi_errno_t { + super::bus_spawn_remote::( + thread, + name, + name_len, + chroot, + args, + args_len, + preopen, + preopen_len, + working_dir, + working_dir_len, + stdin, + stdout, + stderr, + instance, + instance_len, + token, + token_len, + ret_handles, + ) +} + +pub(crate) fn bus_close(thread: &WasiThread, bid: __wasi_bid_t) -> __wasi_errno_t { super::bus_close(thread, bid) } @@ -542,7 +604,9 @@ pub(crate) fn bus_invoke( buf_len: MemoryOffset, ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, ) -> __wasi_errno_t { - super::bus_invoke::(thread, bid, cid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid) + super::bus_invoke::( + thread, bid, cid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, + ) } pub(crate) fn bus_fault( @@ -553,10 +617,7 @@ pub(crate) fn bus_fault( super::bus_fault(thread, cid, fault) } -pub(crate) fn bus_drop( - thread: &WasiThread, - cid: __wasi_cid_t, -) -> __wasi_errno_t { +pub(crate) fn bus_drop(thread: &WasiThread, cid: __wasi_cid_t) -> __wasi_errno_t { super::bus_drop(thread, cid) } @@ -612,7 +673,9 @@ pub(crate) fn bus_poll_data( buf_len: MemoryOffset, ret_evt: WasmPtr<__wasi_busevent_data_t, MemoryType>, ) -> __wasi_errno_t { - super::bus_poll_data::(thread, bid, timeout, topic, topic_len, buf, buf_len, ret_evt) + super::bus_poll_data::( + thread, bid, timeout, topic, topic_len, buf, buf_len, ret_evt, + ) } pub(crate) fn port_bridge( @@ -626,15 +689,11 @@ pub(crate) fn port_bridge( super::port_bridge::(thread, network, network_len, token, token_len, security) } -pub(crate) fn port_unbridge( - thread: &WasiThread, -) -> __wasi_errno_t { +pub(crate) fn port_unbridge(thread: &WasiThread) -> __wasi_errno_t { super::port_unbridge(thread) } -pub(crate) fn port_dhcp_acquire( - thread: &WasiThread, -) -> __wasi_errno_t { +pub(crate) fn port_dhcp_acquire(thread: &WasiThread) -> __wasi_errno_t { super::port_dhcp_acquire(thread) } @@ -652,9 +711,7 @@ pub(crate) fn port_addr_remove( super::port_addr_remove::(thread, addr) } -pub(crate) fn port_addr_clear( - thread: &WasiThread, -) -> __wasi_errno_t { +pub(crate) fn port_addr_clear(thread: &WasiThread) -> __wasi_errno_t { super::port_addr_clear(thread) } @@ -697,9 +754,7 @@ pub(crate) fn port_route_remove( super::port_route_remove::(thread, ip) } -pub(crate) fn port_route_clear( - thread: &WasiThread, -) -> __wasi_errno_t { +pub(crate) fn port_route_clear(thread: &WasiThread) -> __wasi_errno_t { super::port_route_clear(thread) } @@ -731,7 +786,17 @@ pub(crate) fn http_request( gzip: __wasi_bool_t, ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, ) -> __wasi_errno_t { - super::http_request::(thread, url, url_len, method, method_len, headers, headers_len, gzip, ret_handles) + super::http_request::( + thread, + url, + url_len, + method, + method_len, + headers, + headers_len, + gzip, + ret_handles, + ) } pub(crate) fn http_status( @@ -749,7 +814,7 @@ pub(crate) fn http_status( pub(crate) fn sock_status( thread: &WasiThread, sock: __wasi_fd_t, - ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType> + ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType>, ) -> __wasi_errno_t { super::sock_status::(thread, sock, ret_status) } @@ -913,7 +978,15 @@ pub(crate) fn sock_recv( ro_data_len: WasmPtr, ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags) + super::sock_recv::( + thread, + sock, + ri_data, + ri_data_len, + ri_flags, + ro_data_len, + ro_flags, + ) } pub(crate) fn sock_recv_from( @@ -926,7 +999,16 @@ pub(crate) fn sock_recv_from( ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv_from::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags, ro_addr) + super::sock_recv_from::( + thread, + sock, + ri_data, + ri_data_len, + ri_flags, + ro_data_len, + ro_flags, + ro_addr, + ) } pub(crate) fn sock_send( @@ -949,7 +1031,15 @@ pub(crate) fn sock_send_to( addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ret_data_len: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_send_to::(thread, sock, si_data, si_data_len, si_flags, addr, ret_data_len) + super::sock_send_to::( + thread, + sock, + si_data, + si_data_len, + si_flags, + addr, + ret_data_len, + ) } pub(crate) fn sock_send_file( @@ -960,9 +1050,7 @@ pub(crate) fn sock_send_file( count: __wasi_filesize_t, ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - unsafe { - super::sock_send_file::(thread, out_fd, in_fd, offset, count, ret_sent) - } + unsafe { super::sock_send_file::(thread, out_fd, in_fd, offset, count, ret_sent) } } pub(crate) fn sock_shutdown( diff --git a/lib/wasi/src/syscalls/wasix64.rs b/lib/wasi/src/syscalls/wasix64.rs index 0ef06d914a5..6bbd9abb4c7 100644 --- a/lib/wasi/src/syscalls/wasix64.rs +++ b/lib/wasi/src/syscalls/wasix64.rs @@ -1,7 +1,7 @@ #![deny(dead_code)] +use crate::{WasiError, WasiState, WasiThread}; +use wasmer::{Memory, Memory64, MemorySize, WasmPtr, WasmSlice}; use wasmer_wasi_types::*; -use wasmer::{Memory, WasmPtr, WasmSlice, MemorySize, Memory64}; -use crate::{WasiThread, WasiState, WasiError}; type MemoryType = Memory64; type MemoryOffset = u64; @@ -193,7 +193,11 @@ pub(crate) fn fd_readdir( super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) } -pub(crate) fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { +pub(crate) fn fd_renumber( + thread: &WasiThread, + from: __wasi_fd_t, + to: __wasi_fd_t, +) -> __wasi_errno_t { super::fd_renumber(thread, from, to) } @@ -259,7 +263,9 @@ pub(crate) fn path_filestat_set_times( st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { - super::path_filestat_set_times::(thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags) + super::path_filestat_set_times::( + thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, + ) } pub(crate) fn path_link( @@ -272,7 +278,16 @@ pub(crate) fn path_link( new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_link::(thread, old_fd, old_flags, old_path, old_path_len, new_fd, new_path, new_path_len) + super::path_link::( + thread, + old_fd, + old_flags, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len, + ) } pub(crate) fn path_open( @@ -287,7 +302,18 @@ pub(crate) fn path_open( fs_flags: __wasi_fdflags_t, fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::path_open::(thread, dirfd, dirflags, path, path_len, o_flags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) + super::path_open::( + thread, + dirfd, + dirflags, + path, + path_len, + o_flags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd, + ) } pub(crate) fn path_readlink( @@ -320,7 +346,15 @@ pub(crate) fn path_rename( new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_rename::(thread, old_fd, old_path, old_path_len, new_fd, new_path, new_path_len) + super::path_rename::( + thread, + old_fd, + old_path, + old_path_len, + new_fd, + new_path, + new_path_len, + ) } pub(crate) fn path_symlink( @@ -364,7 +398,7 @@ pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_er pub(crate) fn random_get( thread: &WasiThread, buf: WasmPtr, - buf_len: MemoryOffset + buf_len: MemoryOffset, ) -> __wasi_errno_t { super::random_get::(thread, buf, buf_len) } @@ -449,10 +483,7 @@ pub(crate) fn thread_id( super::thread_id::(thread, ret_tid) } -pub(crate) fn thread_join( - thread: &WasiThread, - tid: __wasi_tid_t, -) -> __wasi_errno_t { +pub(crate) fn thread_join(thread: &WasiThread, tid: __wasi_tid_t) -> __wasi_errno_t { super::thread_join(thread, tid) } @@ -497,7 +528,22 @@ pub(crate) fn bus_spawn_local( working_dir_len: MemoryOffset, ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, ) -> __wasi_errno_t { - super::bus_spawn_local::(thread, name, name_len, chroot, args, args_len, preopen, preopen_len, stdin, stdout, stderr, working_dir, working_dir_len, ret_handles) + super::bus_spawn_local::( + thread, + name, + name_len, + chroot, + args, + args_len, + preopen, + preopen_len, + stdin, + stdout, + stderr, + working_dir, + working_dir_len, + ret_handles, + ) } pub(crate) fn bus_spawn_remote( @@ -520,13 +566,29 @@ pub(crate) fn bus_spawn_remote( token_len: MemoryOffset, ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, ) -> __wasi_errno_t { - super::bus_spawn_remote::(thread, name, name_len, chroot, args, args_len, preopen, preopen_len, working_dir, working_dir_len, stdin, stdout, stderr, instance, instance_len, token, token_len, ret_handles) -} - -pub(crate) fn bus_close( - thread: &WasiThread, - bid: __wasi_bid_t, -) -> __wasi_errno_t { + super::bus_spawn_remote::( + thread, + name, + name_len, + chroot, + args, + args_len, + preopen, + preopen_len, + working_dir, + working_dir_len, + stdin, + stdout, + stderr, + instance, + instance_len, + token, + token_len, + ret_handles, + ) +} + +pub(crate) fn bus_close(thread: &WasiThread, bid: __wasi_bid_t) -> __wasi_errno_t { super::bus_close(thread, bid) } @@ -542,7 +604,9 @@ pub(crate) fn bus_invoke( buf_len: MemoryOffset, ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, ) -> __wasi_errno_t { - super::bus_invoke::(thread, bid, cid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid) + super::bus_invoke::( + thread, bid, cid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, + ) } pub(crate) fn bus_fault( @@ -553,10 +617,7 @@ pub(crate) fn bus_fault( super::bus_fault(thread, cid, fault) } -pub(crate) fn bus_drop( - thread: &WasiThread, - cid: __wasi_cid_t, -) -> __wasi_errno_t { +pub(crate) fn bus_drop(thread: &WasiThread, cid: __wasi_cid_t) -> __wasi_errno_t { super::bus_drop(thread, cid) } @@ -612,7 +673,9 @@ pub(crate) fn bus_poll_data( buf_len: MemoryOffset, ret_evt: WasmPtr<__wasi_busevent_data_t, MemoryType>, ) -> __wasi_errno_t { - super::bus_poll_data::(thread, bid, timeout, topic, topic_len, buf, buf_len, ret_evt) + super::bus_poll_data::( + thread, bid, timeout, topic, topic_len, buf, buf_len, ret_evt, + ) } pub(crate) fn port_bridge( @@ -626,15 +689,11 @@ pub(crate) fn port_bridge( super::port_bridge::(thread, network, network_len, token, token_len, security) } -pub(crate) fn port_unbridge( - thread: &WasiThread, -) -> __wasi_errno_t { +pub(crate) fn port_unbridge(thread: &WasiThread) -> __wasi_errno_t { super::port_unbridge(thread) } -pub(crate) fn port_dhcp_acquire( - thread: &WasiThread, -) -> __wasi_errno_t { +pub(crate) fn port_dhcp_acquire(thread: &WasiThread) -> __wasi_errno_t { super::port_dhcp_acquire(thread) } @@ -652,9 +711,7 @@ pub(crate) fn port_addr_remove( super::port_addr_remove::(thread, addr) } -pub(crate) fn port_addr_clear( - thread: &WasiThread, -) -> __wasi_errno_t { +pub(crate) fn port_addr_clear(thread: &WasiThread) -> __wasi_errno_t { super::port_addr_clear(thread) } @@ -697,9 +754,7 @@ pub(crate) fn port_route_remove( super::port_route_remove::(thread, ip) } -pub(crate) fn port_route_clear( - thread: &WasiThread, -) -> __wasi_errno_t { +pub(crate) fn port_route_clear(thread: &WasiThread) -> __wasi_errno_t { super::port_route_clear(thread) } @@ -731,7 +786,17 @@ pub(crate) fn http_request( gzip: __wasi_bool_t, ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, ) -> __wasi_errno_t { - super::http_request::(thread, url, url_len, method, method_len, headers, headers_len, gzip, ret_handles) + super::http_request::( + thread, + url, + url_len, + method, + method_len, + headers, + headers_len, + gzip, + ret_handles, + ) } pub(crate) fn http_status( @@ -749,7 +814,7 @@ pub(crate) fn http_status( pub(crate) fn sock_status( thread: &WasiThread, sock: __wasi_fd_t, - ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType> + ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType>, ) -> __wasi_errno_t { super::sock_status::(thread, sock, ret_status) } @@ -913,7 +978,15 @@ pub(crate) fn sock_recv( ro_data_len: WasmPtr, ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags) + super::sock_recv::( + thread, + sock, + ri_data, + ri_data_len, + ri_flags, + ro_data_len, + ro_flags, + ) } pub(crate) fn sock_recv_from( @@ -926,7 +999,16 @@ pub(crate) fn sock_recv_from( ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_recv_from::(thread, sock, ri_data, ri_data_len, ri_flags, ro_data_len, ro_flags, ro_addr) + super::sock_recv_from::( + thread, + sock, + ri_data, + ri_data_len, + ri_flags, + ro_data_len, + ro_flags, + ro_addr, + ) } pub(crate) fn sock_send( @@ -949,7 +1031,15 @@ pub(crate) fn sock_send_to( addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ret_data_len: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_send_to::(thread, sock, si_data, si_data_len, si_flags, addr, ret_data_len) + super::sock_send_to::( + thread, + sock, + si_data, + si_data_len, + si_flags, + addr, + ret_data_len, + ) } pub(crate) fn sock_send_file( @@ -960,9 +1050,7 @@ pub(crate) fn sock_send_file( count: __wasi_filesize_t, ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - unsafe { - super::sock_send_file::(thread, out_fd, in_fd, offset, count, ret_sent) - } + unsafe { super::sock_send_file::(thread, out_fd, in_fd, offset, count, ret_sent) } } pub(crate) fn sock_shutdown( diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index 11d6d81ec0d..a0ce908b09d 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -1,6 +1,6 @@ +use super::types::*; use std::collections::BTreeSet; use wasmer::Module; -use super::types::*; #[allow(dead_code)] /// Check if a provided module is compiled for some version of WASI. @@ -31,7 +31,7 @@ pub fn map_io_err(err: std::io::Error) -> __wasi_errno_t { ErrorKind::Other => __WASI_EIO, ErrorKind::UnexpectedEof => __WASI_EIO, ErrorKind::Unsupported => __WASI_ENOTSUP, - _ => __WASI_EIO, + _ => __WASI_EIO, } } @@ -104,22 +104,19 @@ impl Ord for WasiVersion { return std::cmp::Ordering::Equal; } match (*self, *other) { - (Self::Snapshot1, Self::Snapshot0) => { - std::cmp::Ordering::Greater - } + (Self::Snapshot1, Self::Snapshot0) => std::cmp::Ordering::Greater, (Self::Wasix32v1, Self::Snapshot1) | (Self::Wasix32v1, Self::Snapshot0) => { std::cmp::Ordering::Greater } - (Self::Wasix64v1, Self::Wasix32v1) | (Self::Wasix64v1, Self::Snapshot1) | (Self::Wasix64v1, Self::Snapshot0) => { - std::cmp::Ordering::Greater - } - (Self::Latest, Self::Wasix64v1) | (Self::Latest, Self::Wasix32v1) | (Self::Latest, Self::Snapshot1) | (Self::Latest, Self::Snapshot0) => { - std::cmp::Ordering::Greater - } + (Self::Wasix64v1, Self::Wasix32v1) + | (Self::Wasix64v1, Self::Snapshot1) + | (Self::Wasix64v1, Self::Snapshot0) => std::cmp::Ordering::Greater, + (Self::Latest, Self::Wasix64v1) + | (Self::Latest, Self::Wasix32v1) + | (Self::Latest, Self::Snapshot1) + | (Self::Latest, Self::Snapshot0) => std::cmp::Ordering::Greater, // they are not equal and not greater so they must be less - (_, _) => { - std::cmp::Ordering::Less - } + (_, _) => std::cmp::Ordering::Less, } } } diff --git a/tests/compilers/config.rs b/tests/compilers/config.rs index 4cb6fce1adb..28c35b7cbf8 100644 --- a/tests/compilers/config.rs +++ b/tests/compilers/config.rs @@ -99,7 +99,10 @@ impl Config { } } - pub fn compiler_config(&self, #[allow(unused_variables)] canonicalize_nans: bool) -> Box { + pub fn compiler_config( + &self, + #[allow(unused_variables)] canonicalize_nans: bool, + ) -> Box { match &self.compiler { #[cfg(feature = "cranelift")] Compiler::Cranelift => { diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 6f4be6fd247..6255e9e0e7e 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -1,8 +1,8 @@ use anyhow::Context; use std::fs::{read_dir, File, OpenOptions, ReadDir}; use std::io::{self, Read, Seek, Write}; -use std::sync::{Arc, Mutex, mpsc}; use std::path::{Path, PathBuf}; +use std::sync::{mpsc, Arc, Mutex}; use wasmer::{Imports, Instance, Module, Store}; use wasmer_vfs::{host_fs, mem_fs, FileSystem}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; @@ -130,7 +130,12 @@ impl<'a> WasiTest<'a> { fn create_wasi_env( &self, filesystem_kind: WasiFileSystemKind, - ) -> anyhow::Result<(WasiEnv, Vec, mpsc::Receiver>, mpsc::Receiver>)> { + ) -> anyhow::Result<( + WasiEnv, + Vec, + mpsc::Receiver>, + mpsc::Receiver>, + )> { let mut builder = WasiState::new(self.wasm_path); let stdin_pipe = Pipe::new(); @@ -524,7 +529,12 @@ struct OutputCapturerer { impl OutputCapturerer { fn new() -> (Self, mpsc::Receiver>) { let (tx, rx) = mpsc::channel(); - (Self { output: Arc::new(Mutex::new(tx)) }, rx) + ( + Self { + output: Arc::new(Mutex::new(tx)), + }, + rx, + ) } } @@ -564,29 +574,32 @@ impl Seek for OutputCapturerer { } impl Write for OutputCapturerer { fn write(&mut self, buf: &[u8]) -> io::Result { - self.output.lock().unwrap().send(buf.to_vec()) - .map_err(|err| io::Error::new( - io::ErrorKind::BrokenPipe, err.to_string(), - ))?; + self.output + .lock() + .unwrap() + .send(buf.to_vec()) + .map_err(|err| io::Error::new(io::ErrorKind::BrokenPipe, err.to_string()))?; Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.output.lock().unwrap().send(buf.to_vec()) - .map_err(|err| io::Error::new( - io::ErrorKind::BrokenPipe, err.to_string(), - ))?; + self.output + .lock() + .unwrap() + .send(buf.to_vec()) + .map_err(|err| io::Error::new(io::ErrorKind::BrokenPipe, err.to_string()))?; Ok(()) } fn write_fmt(&mut self, fmt: std::fmt::Arguments) -> io::Result<()> { let mut buf = Vec::::new(); buf.write_fmt(fmt)?; - self.output.lock().unwrap().send(buf) - .map_err(|err| io::Error::new( - io::ErrorKind::BrokenPipe, err.to_string(), - ))?; + self.output + .lock() + .unwrap() + .send(buf) + .map_err(|err| io::Error::new(io::ErrorKind::BrokenPipe, err.to_string()))?; Ok(()) } } From 68e98e216df7efaed0429d167a500e42bfec613c Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 9 Jun 2022 16:17:23 +0200 Subject: [PATCH 5/9] Put back uint8view as hidden public instead of private --- lib/api/src/js/externals/memory.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/api/src/js/externals/memory.rs b/lib/api/src/js/externals/memory.rs index 033ab9cc6d9..2de3d044db4 100644 --- a/lib/api/src/js/externals/memory.rs +++ b/lib/api/src/js/externals/memory.rs @@ -237,7 +237,9 @@ impl Memory { Ok(Pages(new_pages)) } - pub(crate) fn uint8view(&self) -> js_sys::Uint8Array { + /// Used by tests + #[doc(hidden)] + pub fn uint8view(&self) -> js_sys::Uint8Array { js_sys::Uint8Array::new(&self.vm_memory.memory.buffer()) } From 182b1bd3ff4c63097f3f81b2fbcd53da2beb3f0d Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 10 Jun 2022 16:59:41 +0200 Subject: [PATCH 6/9] wasi: Fixed root folder not being found --- lib/wasi/src/state/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 273b76662e0..13fba0be790 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -913,6 +913,9 @@ impl WasiFs { let path: &Path = Path::new(path); let mut cur_inode = self.get_fd_inode(base)?; + if path.to_str().unwrap() == "/" && base == VIRTUAL_ROOT_FD { + return Ok(cur_inode); + } let n_components = path.components().count(); // If this is the start of the path search and it starts with the From 7bf6d30459a4b23cfc7fb683a0a6bede5a1c74a4 Mon Sep 17 00:00:00 2001 From: John Sharratt's Shared Account Date: Fri, 10 Jun 2022 21:45:28 +0200 Subject: [PATCH 7/9] Added stdin, stdout and stderr methods to WasiState for wasmer consumers And converted the WASI js test into a generic stdio test that works for both sys and js versions of wasmer (also fixed the tests) --- lib/vfs/src/host_fs.rs | 4 +- lib/vfs/src/lib.rs | 6 +- lib/vfs/src/mem_fs/file_opener.rs | 2 +- lib/wasi/src/state/builder.rs | 14 +- lib/wasi/src/state/guard.rs | 292 +++++++++++++++++++++++++++++ lib/wasi/src/state/mod.rs | 114 ++++++----- lib/wasi/src/state/types.rs | 4 +- lib/wasi/tests/{js.rs => stdio.rs} | 92 ++++++--- tests/lib/wast/src/wasi_wast.rs | 4 +- 9 files changed, 427 insertions(+), 105 deletions(-) create mode 100644 lib/wasi/src/state/guard.rs rename lib/wasi/tests/{js.rs => stdio.rs} (73%) diff --git a/lib/vfs/src/host_fs.rs b/lib/vfs/src/host_fs.rs index 37f715ea288..788d21b3b77 100644 --- a/lib/vfs/src/host_fs.rs +++ b/lib/vfs/src/host_fs.rs @@ -181,7 +181,7 @@ impl crate::FileOpener for FileOpener { &mut self, path: &Path, conf: &OpenOptionsConfig, - ) -> Result> { + ) -> Result> { // TODO: handle create implying write, etc. let read = conf.read(); let write = conf.write(); @@ -197,7 +197,7 @@ impl crate::FileOpener for FileOpener { .map_err(Into::into) .map(|file| { Box::new(File::new(file, path.to_owned(), read, write, append)) - as Box + as Box }) } } diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index 0b8456bfda3..927440cd212 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -55,7 +55,7 @@ pub trait FileOpener { &mut self, path: &Path, conf: &OpenOptionsConfig, - ) -> Result>; + ) -> Result>; } #[derive(Debug, Clone)] @@ -150,14 +150,14 @@ impl OpenOptions { self } - pub fn open>(&mut self, path: P) -> Result> { + pub fn open>(&mut self, path: P) -> Result> { self.opener.open(path.as_ref(), &self.conf) } } /// This trait relies on your file closing when it goes out of scope via `Drop` #[cfg_attr(feature = "enable-serde", typetag::serde)] -pub trait VirtualFile: fmt::Debug + Send + Write + Read + Seek + 'static + Upcastable { +pub trait VirtualFile: fmt::Debug + Write + Read + Seek + Upcastable { /// the last time the file was accessed in nanoseconds as a UNIX timestamp fn last_accessed(&self) -> u64; diff --git a/lib/vfs/src/mem_fs/file_opener.rs b/lib/vfs/src/mem_fs/file_opener.rs index 679341badc2..80fc9255b3d 100644 --- a/lib/vfs/src/mem_fs/file_opener.rs +++ b/lib/vfs/src/mem_fs/file_opener.rs @@ -14,7 +14,7 @@ impl crate::FileOpener for FileOpener { &mut self, path: &Path, conf: &OpenOptionsConfig, - ) -> Result> { + ) -> Result> { let read = conf.read(); let mut write = conf.write(); let append = conf.append(); diff --git a/lib/wasi/src/state/builder.rs b/lib/wasi/src/state/builder.rs index 3760b6f67ec..b77d371a1c4 100644 --- a/lib/wasi/src/state/builder.rs +++ b/lib/wasi/src/state/builder.rs @@ -46,9 +46,9 @@ pub struct WasiStateBuilder { vfs_preopens: Vec, #[allow(clippy::type_complexity)] setup_fs_fn: Option Result<(), String> + Send>>, - stdout_override: Option>, - stderr_override: Option>, - stdin_override: Option>, + stdout_override: Option>, + stderr_override: Option>, + stdin_override: Option>, fs_override: Option>, runtime_override: Option>, } @@ -284,7 +284,7 @@ impl WasiStateBuilder { /// Overwrite the default WASI `stdout`, if you want to hold on to the /// original `stdout` use [`WasiFs::swap_file`] after building. - pub fn stdout(&mut self, new_file: Box) -> &mut Self { + pub fn stdout(&mut self, new_file: Box) -> &mut Self { self.stdout_override = Some(new_file); self @@ -292,7 +292,7 @@ impl WasiStateBuilder { /// Overwrite the default WASI `stderr`, if you want to hold on to the /// original `stderr` use [`WasiFs::swap_file`] after building. - pub fn stderr(&mut self, new_file: Box) -> &mut Self { + pub fn stderr(&mut self, new_file: Box) -> &mut Self { self.stderr_override = Some(new_file); self @@ -300,7 +300,7 @@ impl WasiStateBuilder { /// Overwrite the default WASI `stdin`, if you want to hold on to the /// original `stdin` use [`WasiFs::swap_file`] after building. - pub fn stdin(&mut self, new_file: Box) -> &mut Self { + pub fn stdin(&mut self, new_file: Box) -> &mut Self { self.stdin_override = Some(new_file); self @@ -465,7 +465,7 @@ impl WasiStateBuilder { Ok(WasiState { fs: wasi_fs, - inodes, + inodes: Arc::new(inodes), args: self.args.clone(), envs: self .envs diff --git a/lib/wasi/src/state/guard.rs b/lib/wasi/src/state/guard.rs new file mode 100644 index 00000000000..17ec9164a5a --- /dev/null +++ b/lib/wasi/src/state/guard.rs @@ -0,0 +1,292 @@ +use std::{sync::{ + RwLockReadGuard, RwLockWriteGuard +}, io::Seek}; +use super::*; + +#[derive(Debug)] +pub(crate) struct InodeValFileReadGuard<'a> { + pub(crate) guard: RwLockReadGuard<'a, Kind>, +} + +impl<'a> Deref for InodeValFileReadGuard<'a> { + type Target = Option>; + fn deref(&self) -> &Self::Target { + if let Kind::File { handle, .. } = self.guard.deref() { + return handle; + } + unreachable!() + } +} + +#[derive(Debug)] +pub struct InodeValFileWriteGuard<'a> { + pub(crate) guard: RwLockWriteGuard<'a, Kind>, +} + +impl<'a> Deref for InodeValFileWriteGuard<'a> { + type Target = Option>; + fn deref(&self) -> &Self::Target { + if let Kind::File { handle, .. } = self.guard.deref() { + return handle; + } + unreachable!() + } +} + +impl<'a> DerefMut for InodeValFileWriteGuard<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + if let Kind::File { handle, .. } = self.guard.deref_mut() { + return handle; + } + unreachable!() + } +} + +#[derive(Debug)] +pub(crate) struct WasiStateFileGuard { + inodes: Arc>, + inode: generational_arena::Index, +} + +impl WasiStateFileGuard +{ + pub fn new(state: &WasiState, fd: __wasi_fd_t) -> Result { + let inodes = state.inodes.read().unwrap(); + let fd_map = state.fs.fd_map.read().unwrap(); + if let Some(fd) = fd_map.get(&fd) { + let guard = inodes.arena[fd.inode].read(); + if let Kind::File { .. } = guard.deref() { + Ok( + Self { + inodes: state.inodes.clone(), + inode: fd.inode + } + ) + } else { + // Our public API should ensure that this is not possible + Err(FsError::NotAFile) + } + + } else { + Err(FsError::NoDevice) + } + } + + pub fn lock_read<'a>(&self, inodes: &'a RwLockReadGuard) -> InodeValFileReadGuard<'a> + { + let guard = inodes.arena[self.inode].read(); + if let Kind::File { .. } = guard.deref() { + InodeValFileReadGuard { guard } + } else { + // Our public API should ensure that this is not possible + unreachable!("Non-file found in standard device location") + } + } + + pub fn lock_write<'a>(&self, inodes: &'a RwLockReadGuard) -> InodeValFileWriteGuard<'a> + { + let guard = inodes.arena[self.inode].write(); + if let Kind::File { .. } = guard.deref() { + InodeValFileWriteGuard { guard } + } else { + // Our public API should ensure that this is not possible + unreachable!("Non-file found in standard device location") + } + } +} + +impl VirtualFile +for WasiStateFileGuard +{ + fn last_accessed(&self) -> u64 { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.last_accessed() + } else { + 0 + } + } + + fn last_modified(&self) -> u64 { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.last_modified() + } else { + 0 + } + } + + fn created_time(&self) -> u64 { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.created_time() + } else { + 0 + } + } + + fn size(&self) -> u64 { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.size() + } else { + 0 + } + } + + fn set_len(&mut self, new_size: u64) -> Result<(), FsError> { + let inodes = self.inodes.read().unwrap(); + let mut guard = self.lock_write(&inodes); + if let Some(file) = guard.deref_mut() { + file.set_len(new_size) + } else { + Err(FsError::IOError) + } + } + + fn unlink(&mut self) -> Result<(), FsError> { + let inodes = self.inodes.read().unwrap(); + let mut guard = self.lock_write(&inodes); + if let Some(file) = guard.deref_mut() { + file.unlink() + } else { + Err(FsError::IOError) + } + } + + fn sync_to_disk(&self) -> Result<(), FsError> { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.sync_to_disk() + } else { + Err(FsError::IOError) + } + } + + fn bytes_available(&self) -> Result { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.bytes_available() + } else { + Err(FsError::IOError) + } + } + + fn bytes_available_read(&self) -> Result, FsError> { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.bytes_available_read() + } else { + Err(FsError::IOError) + } + } + + fn bytes_available_write(&self) -> Result, FsError> { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.bytes_available_write() + } else { + Err(FsError::IOError) + } + } + + fn is_open(&self) -> bool { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.is_open() + } else { + false + } + } + + fn get_fd(&self) -> Option { + let inodes = self.inodes.read().unwrap(); + let guard = self.lock_read(&inodes); + if let Some(file) = guard.deref() { + file.get_fd() + } else { + None + } + } +} + +impl Write +for WasiStateFileGuard +{ + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let inodes = self.inodes.read().unwrap(); + let mut guard = self.lock_write(&inodes); + if let Some(file) = guard.deref_mut() { + file.write(buf) + } else { + Err(std::io::ErrorKind::Unsupported.into()) + } + } + + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { + let inodes = self.inodes.read().unwrap(); + let mut guard = self.lock_write(&inodes); + if let Some(file) = guard.deref_mut() { + file.write_vectored(bufs) + } else { + Err(std::io::ErrorKind::Unsupported.into()) + } + } + + fn flush(&mut self) -> std::io::Result<()> { + let inodes = self.inodes.read().unwrap(); + let mut guard = self.lock_write(&inodes); + if let Some(file) = guard.deref_mut() { + file.flush() + } else { + Err(std::io::ErrorKind::Unsupported.into()) + } + } +} + +impl Read +for WasiStateFileGuard +{ + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let inodes = self.inodes.read().unwrap(); + let mut guard = self.lock_write(&inodes); + if let Some(file) = guard.deref_mut() { + file.read(buf) + } else { + Err(std::io::ErrorKind::Unsupported.into()) + } + } + + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { + let inodes = self.inodes.read().unwrap(); + let mut guard = self.lock_write(&inodes); + if let Some(file) = guard.deref_mut() { + file.read_vectored(bufs) + } else { + Err(std::io::ErrorKind::Unsupported.into()) + } + } +} + +impl Seek +for WasiStateFileGuard +{ + fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { + let inodes = self.inodes.read().unwrap(); + let mut guard = self.lock_write(&inodes); + if let Some(file) = guard.deref_mut() { + file.seek(pos) + } else { + Err(std::io::ErrorKind::Unsupported.into()) + } + } +} \ No newline at end of file diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 13fba0be790..5a7c08cdfaf 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -19,11 +19,13 @@ mod builder; mod pipe; mod socket; mod types; +mod guard; pub use self::builder::*; pub use self::pipe::*; pub use self::socket::*; pub use self::types::*; +pub use self::guard::*; use crate::syscalls::types::*; use crate::utils::map_io_err; use generational_arena::Arena; @@ -32,6 +34,7 @@ pub use generational_arena::Index as Inode; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::collections::VecDeque; +use std::io::Read; use std::sync::mpsc; use std::sync::Arc; use std::{ @@ -90,45 +93,6 @@ impl InodeVal { } } -#[derive(Debug)] -pub struct InodeValFileReadGuard<'a> { - pub(crate) guard: RwLockReadGuard<'a, Kind>, -} - -impl<'a> Deref for InodeValFileReadGuard<'a> { - type Target = Option>; - fn deref(&self) -> &Self::Target { - if let Kind::File { handle, .. } = self.guard.deref() { - return handle; - } - unreachable!() - } -} - -#[derive(Debug)] -pub struct InodeValFileWriteGuard<'a> { - pub(crate) guard: RwLockWriteGuard<'a, Kind>, -} - -impl<'a> Deref for InodeValFileWriteGuard<'a> { - type Target = Option>; - fn deref(&self) -> &Self::Target { - if let Kind::File { handle, .. } = self.guard.deref() { - return handle; - } - unreachable!() - } -} - -impl<'a> DerefMut for InodeValFileWriteGuard<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - if let Kind::File { handle, .. } = self.guard.deref_mut() { - return handle; - } - unreachable!() - } -} - /// The core of the filesystem abstraction. Includes directories, /// files, and symlinks. #[derive(Debug)] @@ -136,7 +100,7 @@ impl<'a> DerefMut for InodeValFileWriteGuard<'a> { pub enum Kind { File { /// The open file, if it's open - handle: Option>, + handle: Option>, /// The path on the host system where the file is located /// This is deprecated and will be removed soon path: PathBuf, @@ -264,14 +228,14 @@ impl WasiInodes { } /// Get the `VirtualFile` object at stdout - pub fn stdout( + pub(crate) fn stdout( &self, fd_map: &RwLock>, ) -> Result { self.std_dev_get(fd_map, __WASI_STDOUT_FILENO) } /// Get the `VirtualFile` object at stdout mutably - pub fn stdout_mut( + pub(crate) fn stdout_mut( &self, fd_map: &RwLock>, ) -> Result { @@ -279,14 +243,14 @@ impl WasiInodes { } /// Get the `VirtualFile` object at stderr - pub fn stderr( + pub(crate) fn stderr( &self, fd_map: &RwLock>, ) -> Result { self.std_dev_get(fd_map, __WASI_STDERR_FILENO) } /// Get the `VirtualFile` object at stderr mutably - pub fn stderr_mut( + pub(crate) fn stderr_mut( &self, fd_map: &RwLock>, ) -> Result { @@ -294,14 +258,14 @@ impl WasiInodes { } /// Get the `VirtualFile` object at stdin - pub fn stdin( + pub(crate) fn stdin( &self, fd_map: &RwLock>, ) -> Result { self.std_dev_get(fd_map, __WASI_STDIN_FILENO) } /// Get the `VirtualFile` object at stdin mutably - pub fn stdin_mut( + pub(crate) fn stdin_mut( &self, fd_map: &RwLock>, ) -> Result { @@ -310,18 +274,18 @@ impl WasiInodes { /// Internal helper function to get a standard device handle. /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. - fn std_dev_get( - &self, + fn std_dev_get<'a>( + &'a self, fd_map: &RwLock>, fd: __wasi_fd_t, - ) -> Result { + ) -> Result, FsError> { if let Some(fd) = fd_map.read().unwrap().get(&fd) { let guard = self.arena[fd.inode].read(); if let Kind::File { .. } = guard.deref() { Ok(InodeValFileReadGuard { guard }) } else { // Our public API should ensure that this is not possible - unreachable!("Non-file found in standard device location") + Err(FsError::NotAFile) } } else { // this should only trigger if we made a mistake in this crate @@ -330,18 +294,18 @@ impl WasiInodes { } /// Internal helper function to mutably get a standard device handle. /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. - fn std_dev_get_mut( - &self, + fn std_dev_get_mut<'a>( + &'a self, fd_map: &RwLock>, fd: __wasi_fd_t, - ) -> Result { + ) -> Result, FsError> { if let Some(fd) = fd_map.read().unwrap().get(&fd) { let guard = self.arena[fd.inode].write(); if let Kind::File { .. } = guard.deref() { Ok(InodeValFileWriteGuard { guard }) } else { // Our public API should ensure that this is not possible - unreachable!("Non-file found in standard device location") + Err(FsError::NotAFile) } } else { // this should only trigger if we made a mistake in this crate @@ -739,7 +703,7 @@ impl WasiFs { &mut self, inodes: &mut WasiInodes, base: __wasi_fd_t, - file: Box, + file: Box, open_flags: u16, name: String, rights: __wasi_rights_t, @@ -797,8 +761,8 @@ impl WasiFs { &self, inodes: &WasiInodes, fd: __wasi_fd_t, - file: Box, - ) -> Result>, FsError> { + file: Box, + ) -> Result>, FsError> { let mut ret = Some(file); match fd { __WASI_STDIN_FILENO => { @@ -1599,7 +1563,7 @@ impl WasiFs { fn create_std_dev_inner( &self, inodes: &mut WasiInodes, - handle: Box, + handle: Box, name: &'static str, raw_fd: __wasi_fd_t, rights: __wasi_rights_t, @@ -1859,7 +1823,7 @@ impl WasiState { #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct WasiState { pub fs: WasiFs, - pub inodes: RwLock, + pub inodes: Arc>, pub args: Vec>, pub envs: Vec>, } @@ -1883,6 +1847,38 @@ impl WasiState { pub fn unfreeze(bytes: &[u8]) -> Option { bincode::deserialize(bytes).ok() } + + /// Get the `VirtualFile` object at stdout + pub fn stdout( + &self, + ) -> Result, FsError> { + self.std_dev_get(__WASI_STDOUT_FILENO) + } + + /// Get the `VirtualFile` object at stderr + pub fn stderr( + &self, + ) -> Result, FsError> { + self.std_dev_get(__WASI_STDERR_FILENO) + } + + /// Get the `VirtualFile` object at stdin + pub fn stdin( + &self, + ) -> Result, FsError> { + self.std_dev_get(__WASI_STDIN_FILENO) + } + + /// Internal helper function to get a standard device handle. + /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. + fn std_dev_get( + &self, + fd: __wasi_fd_t, + ) -> Result, FsError> { + Ok( + Box::new(WasiStateFileGuard::new(self, fd)?) + ) + } } pub fn virtual_file_type_to_wasi_file_type(file_type: wasmer_vfs::FileType) -> __wasi_filetype_t { diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index cba0b4de83f..58d270c5c95 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -219,7 +219,7 @@ impl PollEventBuilder { #[cfg(all(unix, feature = "sys-poll"))] pub(crate) fn poll( - selfs: &[&(dyn VirtualFile + Sync)], + selfs: &[&(dyn VirtualFile + Send + Sync + 'static)], events: &[PollEventSet], seen_events: &mut [PollEventSet], timeout: Duration, @@ -259,7 +259,7 @@ pub(crate) fn poll( #[cfg(any(not(unix), not(feature = "sys-poll")))] pub(crate) fn poll( - files: &[&(dyn VirtualFile + Sync)], + files: &[&(dyn VirtualFile + Send + Sync + 'static)], events: &[PollEventSet], seen_events: &mut [PollEventSet], timeout: Duration, diff --git a/lib/wasi/tests/js.rs b/lib/wasi/tests/stdio.rs similarity index 73% rename from lib/wasi/tests/js.rs rename to lib/wasi/tests/stdio.rs index fd1c80f831e..fcbbf99e733 100644 --- a/lib/wasi/tests/js.rs +++ b/lib/wasi/tests/stdio.rs @@ -1,10 +1,45 @@ -#![cfg(feature = "js")] +use std::io::{Read, Write}; +#[cfg(feature = "js")] use wasm_bindgen_test::*; use wasmer::{Instance, Module, Store}; -use wasmer_wasi::{Stdin, Stdout, WasiState}; +use wasmer_wasi::{Pipe, WasiState}; + +mod sys { + #[test] + fn test_stdout() { + super::test_stdout() + } + + #[test] + fn test_stdin() { + super::test_stdin() + } + + #[test] + fn test_env() { + super::test_env() + } +} + +#[cfg(feature = "js")] +mod js { + #[wasm_bindgen_test] + fn test_stdout() { + super::test_stdout() + } + + #[wasm_bindgen_test] + fn test_stdin() { + super::test_stdin() + } + + #[wasm_bindgen_test] + fn test_env() { + super::test_env() + } +} -#[wasm_bindgen_test] fn test_stdout() { let store = Store::default(); let module = Module::new(&store, br#" @@ -38,10 +73,10 @@ fn test_stdout() { "#).unwrap(); // Create the `WasiEnv`. - // let stdout = Stdout::default(); + let mut stdout = Pipe::default(); let wasi_env = WasiState::new("command-name") .args(&["Gordon"]) - // .stdout(Box::new(stdout)) + .stdout(Box::new(stdout.clone())) .finalize() .unwrap(); @@ -56,17 +91,17 @@ fn test_stdout() { let start = instance.exports.get_function("_start").unwrap(); start.call(&[]).unwrap(); - let state = wasi_env.state(); - let stdout = state.fs.stdout().unwrap().as_ref().unwrap(); - let stdout = stdout.downcast_ref::().unwrap(); - let stdout_as_str = std::str::from_utf8(&stdout.buf).unwrap(); + let mut stdout_str = String::new(); + stdout.read_to_string(&mut stdout_str).unwrap(); + let stdout_as_str = stdout_str.as_str(); assert_eq!(stdout_as_str, "hello world\n"); } -#[wasm_bindgen_test] + fn test_env() { let store = Store::default(); let module = Module::new(&store, include_bytes!("envvar.wasm")).unwrap(); + #[cfg(feature = "js")] tracing_wasm::set_as_global_default_with_config({ let mut builder = tracing_wasm::WASMLayerConfigBuilder::new(); builder.set_console_config(tracing_wasm::ConsoleConfig::ReportWithoutConsoleColor); @@ -74,7 +109,7 @@ fn test_env() { }); // Create the `WasiEnv`. - // let stdout = Stdout::default(); + let mut stdout = Pipe::new(); let mut wasi_state_builder = WasiState::new("command-name"); wasi_state_builder .args(&["Gordon"]) @@ -83,7 +118,7 @@ fn test_env() { .env("TEST2", "VALUE2"); // panic!("envs: {:?}", wasi_state_builder.envs); let wasi_env = wasi_state_builder - // .stdout(Box::new(stdout)) + .stdout(Box::new(stdout.clone())) .finalize() .unwrap(); @@ -98,28 +133,30 @@ fn test_env() { let start = instance.exports.get_function("_start").unwrap(); start.call(&[]).unwrap(); - let state = wasi_env.state(); - let stdout = state.fs.stdout().unwrap().as_ref().unwrap(); - let stdout = stdout.downcast_ref::().unwrap(); - let stdout_as_str = std::str::from_utf8(&stdout.buf).unwrap(); + let mut stdout_str = String::new(); + stdout.read_to_string(&mut stdout_str).unwrap(); + let stdout_as_str = stdout_str.as_str(); assert_eq!(stdout_as_str, "Env vars:\nDOG=X\nTEST2=VALUE2\nTEST=VALUE\nDOG Ok(\"X\")\nDOG_TYPE Err(NotPresent)\nSET VAR Ok(\"HELLO\")\n"); } -#[wasm_bindgen_test] fn test_stdin() { let store = Store::default(); let module = Module::new(&store, include_bytes!("stdin-hello.wasm")).unwrap(); // Create the `WasiEnv`. - let mut stdin = Stdin::default(); - stdin.buf = "Hello, stdin!".as_bytes().to_owned(); - let mut wasi_env = WasiState::new("command-name") - .stdin(Box::new(stdin)) + let mut stdin = Pipe::new(); + let wasi_env = WasiState::new("command-name") + .stdin(Box::new(stdin.clone())) .finalize() .unwrap(); + // Write to STDIN + let buf = "Hello, stdin!\n".as_bytes().to_owned(); + stdin.write(&buf[..]).unwrap(); + // Generate an `ImportObject`. - let import_object = wasi_env.import_object(&module).unwrap(); + let mut wasi_thread = wasi_env.new_thread(); + let import_object = wasi_thread.import_object(&module).unwrap(); // Let's instantiate the module with the imports. let instance = Instance::new(&module, &import_object).unwrap(); @@ -127,11 +164,10 @@ fn test_stdin() { // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); let result = start.call(&[]); - assert!(result.is_err()); - // let status = result.unwrap_err().downcast::().unwrap(); - let state = wasi_env.state(); - let stdin = state.fs.stdin().unwrap().as_ref().unwrap(); - let stdin = stdin.downcast_ref::().unwrap(); + assert!(result.is_err() == false); + // We assure stdin is now empty - assert_eq!(stdin.buf.len(), 0); + let mut buf = Vec::new(); + stdin.read_to_end(&mut buf).unwrap(); + assert_eq!(buf.len(), 0); } diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 6255e9e0e7e..45b03921be0 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -90,9 +90,7 @@ impl<'a> WasiTest<'a> { if let Some(stdin) = &self.stdin { let state = env.state(); - let inodes = state.inodes.write().unwrap(); - let mut wasi_stdin = inodes.stdin_mut(&state.fs.fd_map)?; - let wasi_stdin = wasi_stdin.as_mut().unwrap(); + let mut wasi_stdin = state.stdin().unwrap(); // Then we can write to it! write!(wasi_stdin, "{}", stdin.stream)?; } From b0709e41536ee81557ceab25cfb918794b029fe7 Mon Sep 17 00:00:00 2001 From: Johnathan Sharratt Date: Sat, 14 May 2022 23:58:04 +0200 Subject: [PATCH 8/9] Implemented multithreading and fixed a number of bugs with WASIX --- examples/wasi.rs | 5 +- examples/wasi_pipes.rs | 5 +- lib/c-api/examples/early-exit.c | 10 +- lib/c-api/examples/wasi.c | 18 +- lib/c-api/src/wasm_c_api/unstable/wasi.rs | 5 +- .../src/wasm_c_api/wasi/capture_files.rs | 93 -- lib/c-api/src/wasm_c_api/wasi/mod.rs | 53 +- lib/cli/src/commands/run/wasi.rs | 14 +- lib/cli/src/commands/wasmer_create_exe_main.c | 12 +- lib/engine-staticlib/README.md | 12 +- lib/vbus/src/lib.rs | 37 +- lib/vfs/src/lib.rs | 23 +- lib/vm/src/instance/mod.rs | 2 +- lib/wasi-types/src/bus.rs | 59 +- lib/wasi/src/lib.rs | 955 +++++++------- lib/wasi/src/macros.rs | 31 + lib/wasi/src/runtime.rs | 21 +- lib/wasi/src/state/builder.rs | 1 + lib/wasi/src/state/guard.rs | 16 +- lib/wasi/src/state/mod.rs | 131 +- lib/wasi/src/state/types.rs | 51 + lib/wasi/src/syscalls/legacy/snapshot0.rs | 29 +- lib/wasi/src/syscalls/mod.rs | 1155 ++++++++++------- lib/wasi/src/syscalls/wasi.rs | 186 ++- lib/wasi/src/syscalls/wasix32.rs | 557 ++++---- lib/wasi/src/syscalls/wasix64.rs | 557 ++++---- lib/wasi/src/utils.rs | 12 + lib/wasi/tests/stdio.rs | 19 +- .../tests/staticlib_engine_test_c_source.c | 12 +- tests/lib/wast/src/wasi_wast.rs | 7 +- 30 files changed, 2188 insertions(+), 1900 deletions(-) delete mode 100644 lib/c-api/src/wasm_c_api/wasi/capture_files.rs diff --git a/examples/wasi.rs b/examples/wasi.rs index d886a2acc87..3d24c5af60b 100644 --- a/examples/wasi.rs +++ b/examples/wasi.rs @@ -40,7 +40,7 @@ fn main() -> Result<(), Box> { println!("Creating `WasiEnv`..."); // First, we create the `WasiEnv` - let wasi_env = WasiState::new("hello") + let mut wasi_env = WasiState::new("hello") // .args(&["world"]) // .env("KEY", "Value") .finalize()?; @@ -48,8 +48,7 @@ fn main() -> Result<(), Box> { println!("Instantiating module with WASI imports..."); // Then, we get the import object related to our WASI // and attach it to the Wasm instance. - let mut wasi_thread = wasi_env.new_thread(); - let import_object = wasi_thread.import_object(&module)?; + let import_object = wasi_env.import_object(&module)?; let instance = Instance::new(&module, &import_object)?; println!("Call WASI `_start` function..."); diff --git a/examples/wasi_pipes.rs b/examples/wasi_pipes.rs index b198843caf1..fa4cad6973b 100644 --- a/examples/wasi_pipes.rs +++ b/examples/wasi_pipes.rs @@ -39,7 +39,7 @@ fn main() -> Result<(), Box> { // First, we create the `WasiEnv` with the stdio pipes let mut input = Pipe::new(); let mut output = Pipe::new(); - let wasi_env = WasiState::new("hello") + let mut wasi_env = WasiState::new("hello") .stdin(Box::new(input.clone())) .stdout(Box::new(output.clone())) .finalize()?; @@ -47,8 +47,7 @@ fn main() -> Result<(), Box> { println!("Instantiating module with WASI imports..."); // Then, we get the import object related to our WASI // and attach it to the Wasm instance. - let mut wasi_thread = wasi_env.new_thread(); - let import_object = wasi_thread.import_object(&module)?; + let import_object = wasi_env.import_object(&module)?; let instance = Instance::new(&module, &import_object)?; let msg = "racecar go zoom"; diff --git a/lib/c-api/examples/early-exit.c b/lib/c-api/examples/early-exit.c index b4479fc6143..d2410ca8baf 100644 --- a/lib/c-api/examples/early-exit.c +++ b/lib/c-api/examples/early-exit.c @@ -10,10 +10,12 @@ // Use the last_error API to retrieve error messages void print_wasmer_error() { int error_len = wasmer_last_error_length(); - printf("Error len: `%d`\n", error_len); - char *error_str = malloc(error_len); - wasmer_last_error_message(error_str, error_len); - printf("Error str: `%s`\n", error_str); + if (error_len > 0) { + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); + } } void print_frame(wasm_frame_t* frame) { diff --git a/lib/c-api/examples/wasi.c b/lib/c-api/examples/wasi.c index e3047912dca..941a769135e 100644 --- a/lib/c-api/examples/wasi.c +++ b/lib/c-api/examples/wasi.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -12,13 +13,16 @@ void print_wasmer_error() { int error_len = wasmer_last_error_length(); - printf("Error len: `%d`\n", error_len); - char *error_str = malloc(error_len); - wasmer_last_error_message(error_str, error_len); - printf("Error str: `%s`\n", error_str); + if (error_len > 0) { + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); + } } int main(int argc, const char* argv[]) { + // Initialize. printf("Initializing...\n"); wasm_engine_t* engine = wasm_engine_new(); @@ -119,6 +123,7 @@ int main(int argc, const char* argv[]) { printf("> Error calling function!\n"); return 1; } + printf("Call completed\n"); { FILE *memory_stream; @@ -137,6 +142,11 @@ int main(int argc, const char* argv[]) { do { data_read_size = wasi_env_read_stdout(wasi_env, buffer, BUF_SIZE); + if (data_read_size == -1) { + printf("failed to read stdout: %s\n", strerror(errno)); + print_wasmer_error(); + return -1; + } if (data_read_size > 0) { stdout_size += data_read_size; diff --git a/lib/c-api/src/wasm_c_api/unstable/wasi.rs b/lib/c-api/src/wasm_c_api/unstable/wasi.rs index 6970f722a63..f2d1b944713 100644 --- a/lib/c-api/src/wasm_c_api/unstable/wasi.rs +++ b/lib/c-api/src/wasm_c_api/unstable/wasi.rs @@ -6,7 +6,7 @@ use super::super::{ wasi::wasi_env_t, }; use wasmer_api::{Exportable, Extern}; -use wasmer_wasi::{generate_import_object_from_thread, get_wasi_version}; +use wasmer_wasi::{generate_import_object_from_env, get_wasi_version}; /// Unstable non-standard type wrapping `wasm_extern_t` with the /// addition of two `wasm_name_t` respectively for the module name and @@ -170,8 +170,7 @@ fn wasi_get_unordered_imports_inner( let version = c_try!(get_wasi_version(&module.inner, false) .ok_or("could not detect a WASI version on the given module")); - let thread = wasi_env.inner.new_thread(); - let import_object = generate_import_object_from_thread(store, thread, version); + let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); imports.set_buffer( import_object diff --git a/lib/c-api/src/wasm_c_api/wasi/capture_files.rs b/lib/c-api/src/wasm_c_api/wasi/capture_files.rs deleted file mode 100644 index 85ae72dd1e3..00000000000 --- a/lib/c-api/src/wasm_c_api/wasi/capture_files.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! Default implementations for capturing the stdout/stderr output of a WASI program. - -use std::collections::VecDeque; -use std::io::{self, Read, Seek, Write}; -use wasmer_wasi::{WasiFile, WasiFsError}; - -/// For capturing stdout/stderr. Stores all output in a string. -#[derive(Debug)] -pub struct OutputCapturer { - pub(crate) buffer: VecDeque, -} - -impl OutputCapturer { - pub fn new() -> Self { - Self { - buffer: VecDeque::new(), - } - } -} - -impl WasiFile for OutputCapturer { - fn last_accessed(&self) -> u64 { - 0 - } - fn last_modified(&self) -> u64 { - 0 - } - fn created_time(&self) -> u64 { - 0 - } - fn size(&self) -> u64 { - 0 - } - fn set_len(&mut self, _len: u64) -> Result<(), WasiFsError> { - Ok(()) - } - fn unlink(&mut self) -> Result<(), WasiFsError> { - Ok(()) - } - fn bytes_available(&self) -> Result { - // return an arbitrary amount - Ok(1024) - } -} - -// fail when reading or Seeking -impl Read for OutputCapturer { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Err(io::Error::new( - io::ErrorKind::Other, - "can not read from capturing stdout", - )) - } - fn read_to_end(&mut self, _buf: &mut Vec) -> std::io::Result { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "can not read from capturing stdout", - )) - } - fn read_to_string(&mut self, _buf: &mut String) -> io::Result { - Err(io::Error::new( - io::ErrorKind::Other, - "can not read from capturing stdout", - )) - } - fn read_exact(&mut self, _buf: &mut [u8]) -> io::Result<()> { - Err(io::Error::new( - io::ErrorKind::Other, - "can not read from capturing stdout", - )) - } -} -impl Seek for OutputCapturer { - fn seek(&mut self, _pos: io::SeekFrom) -> io::Result { - Err(io::Error::new( - io::ErrorKind::Other, - "can not seek capturing stdout", - )) - } -} -impl Write for OutputCapturer { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.buffer.extend(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.buffer.extend(buf); - Ok(()) - } -} diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 11e2f800207..8c5244a9c9f 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -2,8 +2,6 @@ //! //! This API will be superseded by a standard WASI API when/if such a standard is created. -mod capture_files; - pub use super::unstable::wasi::wasi_get_unordered_imports; use super::{ externals::{wasm_extern_vec_t, wasm_func_t}, @@ -12,15 +10,14 @@ use super::{ store::wasm_store_t, }; use crate::error::update_last_error; -use std::cmp::min; use std::convert::TryFrom; use std::ffi::CStr; use std::os::raw::c_char; use std::slice; use wasmer_api::{Exportable, Extern}; use wasmer_wasi::{ - generate_import_object_from_thread, get_wasi_version, WasiEnv, WasiFile, WasiState, - WasiStateBuilder, WasiVersion, + generate_import_object_from_env, get_wasi_version, WasiEnv, WasiFile, WasiState, + WasiStateBuilder, WasiVersion, Pipe, }; #[derive(Debug)] @@ -177,13 +174,13 @@ pub extern "C" fn wasi_env_new(mut config: Box) -> Option isize { let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len as usize); - let mut state = env.inner.state(); + let state = env.inner.state(); - let stdout = if let Ok(stdout) = state.fs.stdout_mut() { + if let Ok(mut stdout) = state.stdout() { if let Some(stdout) = stdout.as_mut() { - stdout + read_inner(stdout, inner_buffer) } else { update_last_error("could not find a file handle for `stdout`"); return -1; } } else { + update_last_error("could not find a file handle for `stdout`"); return -1; - }; - read_inner(stdout, inner_buffer) + } } #[no_mangle] @@ -228,11 +225,10 @@ pub unsafe extern "C" fn wasi_env_read_stderr( buffer_len: usize, ) -> isize { let inner_buffer = slice::from_raw_parts_mut(buffer as *mut _, buffer_len as usize); - let mut state = env.inner.state(); - let inodes = state.inodes.write().unwrap(); - let stderr = if let Ok(stderr) = inodes.stderr_mut(&state.fs.fd_map) { + let state = env.inner.state(); + if let Ok(mut stderr) = state.stderr() { if let Some(stderr) = stderr.as_mut() { - stderr + read_inner(stderr, inner_buffer) } else { update_last_error("could not find a file handle for `stderr`"); return -1; @@ -240,24 +236,16 @@ pub unsafe extern "C" fn wasi_env_read_stderr( } else { update_last_error("could not find a file handle for `stderr`"); return -1; - }; - read_inner(stderr, inner_buffer) + } } -fn read_inner(wasi_file: &mut Box, inner_buffer: &mut [u8]) -> isize { - if let Some(oc) = wasi_file.downcast_mut::() { - let total_to_read = min(inner_buffer.len(), oc.buffer.len()); - - for (address, value) in inner_buffer - .iter_mut() - .zip(oc.buffer.drain(..total_to_read)) - { - *address = value; +fn read_inner(wasi_file: &mut Box, inner_buffer: &mut [u8]) -> isize { + match wasi_file.read(inner_buffer) { + Ok(a) => a as isize, + Err(err) => { + update_last_error(format!("failed to read wasi_file: {}", err)); + -1 } - - total_to_read as isize - } else { - -1 } } @@ -356,8 +344,7 @@ fn wasi_get_imports_inner( let version = c_try!(get_wasi_version(&module.inner, false) .ok_or("could not detect a WASI version on the given module")); - let mut thread = wasi_env.inner.new_thread(); - let import_object = generate_import_object_from_thread(store, thread, version); + let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); imports.set_buffer(c_try!(module .inner diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index bee664457bb..3e987366b8f 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -3,7 +3,7 @@ use anyhow::Result; use std::collections::BTreeSet; use std::path::PathBuf; use wasmer::{Instance, Module, RuntimeError, Val}; -use wasmer_wasi::{get_wasi_versions, WasiError, WasiState, WasiVersion}; +use wasmer_wasi::{get_wasi_versions, is_wasix_module, WasiError, WasiState, WasiVersion}; use structopt::StructOpt; @@ -96,10 +96,14 @@ impl Wasi { } } - let wasi_env = wasi_state_builder.finalize()?; - let mut wasi_thread = wasi_env.new_thread(); - let import_object = wasi_thread.import_object_for_all_wasi_versions(module)?; - let instance = Instance::new(module, &import_object)?; + let mut wasi_env = wasi_state_builder.finalize()?; + wasi_env.state.fs.is_wasix.store( + is_wasix_module(&module), + std::sync::atomic::Ordering::Release, + ); + + let import_object = wasi_env.import_object_for_all_wasi_versions(module)?; + let instance = Instance::new(&module, &import_object)?; Ok(instance) } diff --git a/lib/cli/src/commands/wasmer_create_exe_main.c b/lib/cli/src/commands/wasmer_create_exe_main.c index c77fcab9dd7..3661ffa9d29 100644 --- a/lib/cli/src/commands/wasmer_create_exe_main.c +++ b/lib/cli/src/commands/wasmer_create_exe_main.c @@ -12,11 +12,13 @@ static void print_wasmer_error() { int error_len = wasmer_last_error_length(); - printf("Error len: `%d`\n", error_len); - char *error_str = (char *)malloc(error_len); - wasmer_last_error_message(error_str, error_len); - printf("%s\n", error_str); - free(error_str); + if (error_len > 0) { + printf("Error len: `%d`\n", error_len); + char *error_str = (char *)malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("%s\n", error_str); + free(error_str); + } } #ifdef WASI diff --git a/lib/engine-staticlib/README.md b/lib/engine-staticlib/README.md index 9c1cc0dbd74..e8566f0137b 100644 --- a/lib/engine-staticlib/README.md +++ b/lib/engine-staticlib/README.md @@ -40,11 +40,13 @@ Now let's create a program to link with this static object file. static void print_wasmer_error() { int error_len = wasmer_last_error_length(); - printf("Error len: `%d`\n", error_len); - char* error_str = (char*) malloc(error_len); - wasmer_last_error_message(error_str, error_len); - printf("Error str: `%s`\n", error_str); - free(error_str); + if (error_len > 0) { + printf("Error len: `%d`\n", error_len); + char* error_str = (char*) malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); + free(error_str); + } } int main() { diff --git a/lib/vbus/src/lib.rs b/lib/vbus/src/lib.rs index 4f3f23d9b3c..0852a3e57be 100644 --- a/lib/vbus/src/lib.rs +++ b/lib/vbus/src/lib.rs @@ -10,11 +10,19 @@ pub type Result = std::result::Result; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] -pub struct BusDescriptor(usize); +pub struct CallDescriptor(u32); -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct CallDescriptor(usize); +impl CallDescriptor { + pub fn raw(&self) -> u32 { + self.0 + } +} + +impl From for CallDescriptor { + fn from(a: u32) -> Self { + Self(a) + } +} pub trait VirtualBus: fmt::Debug + Send + Sync + 'static { /// Starts a new WAPM sub process @@ -31,6 +39,7 @@ pub trait VirtualBusSpawner { #[derive(Debug, Clone)] pub struct SpawnOptionsConfig { + reuse: bool, chroot: bool, args: Vec, preopen: Vec, @@ -43,6 +52,10 @@ pub struct SpawnOptionsConfig { } impl SpawnOptionsConfig { + pub const fn reuse(&self) -> bool { + self.reuse + } + pub const fn chroot(&self) -> bool { self.chroot } @@ -90,6 +103,7 @@ impl SpawnOptions { Self { spawner, conf: SpawnOptionsConfig { + reuse: false, chroot: false, args: Vec::new(), preopen: Vec::new(), @@ -107,6 +121,16 @@ impl SpawnOptions { self } + pub fn reuse(&mut self, reuse: bool) -> &mut Self { + self.conf.reuse = reuse; + self + } + + pub fn chroot(&mut self, chroot: bool) -> &mut Self { + self.conf.chroot = chroot; + self + } + pub fn args(&mut self, args: Vec) -> &mut Self { self.conf.args = args; self @@ -155,8 +179,6 @@ impl SpawnOptions { #[derive(Debug)] pub struct BusSpawnedProcess { - /// Handle of the instance - pub handle: BusDescriptor, /// Reference to the spawned instance pub inst: Box, } @@ -330,6 +352,9 @@ pub enum BusError { /// Invocation has failed #[error("invocation has failed")] InvokeFailed, + /// Already consumed + #[error("already consumed")] + AlreadyConsumed, /// Memory access violation #[error("memory access violation")] MemoryAccessViolation, diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index 927440cd212..65e725215df 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -22,6 +22,18 @@ pub type Result = std::result::Result; #[repr(transparent)] pub struct FileDescriptor(usize); +impl From for FileDescriptor { + fn from(a: u32) -> Self { + Self(a as usize) + } +} + +impl Into for FileDescriptor { + fn into(self) -> u32 { + self.0 as u32 + } +} + pub trait FileSystem: fmt::Debug + Send + Sync + 'static + Upcastable { fn read_dir(&self, path: &Path) -> Result; fn create_dir(&self, path: &Path) -> Result<()>; @@ -238,17 +250,6 @@ impl Upcastable for T { } } -impl dyn VirtualFile + 'static { - #[inline] - pub fn downcast_ref(&'_ self) -> Option<&'_ T> { - self.upcast_any_ref().downcast_ref::() - } - #[inline] - pub fn downcast_mut(&'_ mut self) -> Option<&'_ mut T> { - self.upcast_any_mut().downcast_mut::() - } -} - /// Determines the mode that stdio handlers will operate in #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum StdioMode { diff --git a/lib/vm/src/instance/mod.rs b/lib/vm/src/instance/mod.rs index c224b0ff4c7..f7671196694 100644 --- a/lib/vm/src/instance/mod.rs +++ b/lib/vm/src/instance/mod.rs @@ -859,7 +859,7 @@ impl Instance { /// /// This is more or less a public facade of the private `Instance`, /// providing useful higher-level API. -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct InstanceHandle { /// The [`InstanceRef`]. See its documentation to learn more. instance: InstanceRef, diff --git a/lib/wasi-types/src/bus.rs b/lib/wasi-types/src/bus.rs index bdbd7bcfa6d..ff8bea2ecb3 100644 --- a/lib/wasi-types/src/bus.rs +++ b/lib/wasi-types/src/bus.rs @@ -2,11 +2,6 @@ use super::*; use wasmer_derive::ValueType; use wasmer_types::MemorySize; -pub type __wasi_busdatatype_t = u8; -pub const __WASI_BUS_DATA_TYPE_CALL: __wasi_busdatatype_t = 0; -pub const __WASI_BUS_DATA_TYPE_CALLBACK: __wasi_busdatatype_t = 1; -pub const __WASI_BUS_DATA_TYPE_REPLY: __wasi_busdatatype_t = 2; - pub type __wasi_busdataformat_t = u8; pub const __WASI_BUS_DATA_FORMAT_RAW: __wasi_busdataformat_t = 0; pub const __WASI_BUS_DATA_FORMAT_BINCODE: __wasi_busdataformat_t = 1; @@ -14,11 +9,15 @@ pub const __WASI_BUS_DATA_FORMAT_MESSAGE_PACK: __wasi_busdataformat_t = 2; pub const __WASI_BUS_DATA_FORMAT_JSON: __wasi_busdataformat_t = 3; pub const __WASI_BUS_DATA_FORMAT_YAML: __wasi_busdataformat_t = 4; pub const __WASI_BUS_DATA_FORMAT_XML: __wasi_busdataformat_t = 5; +pub const __WASI_BUS_DATA_FORMAT_RKYV: __wasi_busdataformat_t = 6; pub type __wasi_buseventtype_t = u8; -pub const __WASI_BUS_EVENT_TYPE_EXIT: __wasi_buseventtype_t = 0; -pub const __WASI_BUS_EVENT_TYPE_DATA: __wasi_buseventtype_t = 1; -pub const __WASI_BUS_EVENT_TYPE_FAULT: __wasi_buseventtype_t = 2; +pub const __WASI_BUS_EVENT_TYPE_NOOP: __wasi_buseventtype_t = 0; +pub const __WASI_BUS_EVENT_TYPE_EXIT: __wasi_buseventtype_t = 1; +pub const __WASI_BUS_EVENT_TYPE_CALL: __wasi_buseventtype_t = 2; +pub const __WASI_BUS_EVENT_TYPE_RESULT: __wasi_buseventtype_t = 3; +pub const __WASI_BUS_EVENT_TYPE_FAULT: __wasi_buseventtype_t = 4; +pub const __WASI_BUS_EVENT_TYPE_CLOSE: __wasi_buseventtype_t = 5; pub type __wasi_bid_t = u32; @@ -31,6 +30,13 @@ pub struct __wasi_option_bid_t { pub type __wasi_cid_t = u8; +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_option_fd_t { + pub tag: __wasi_option_t, + pub fd: __wasi_fd_t, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] pub struct __wasi_option_cid_t { @@ -41,25 +47,37 @@ pub struct __wasi_option_cid_t { #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] pub struct __wasi_bus_handles_t { - pub handle: __wasi_bid_t, - pub stdin: __wasi_fd_t, - pub stdout: __wasi_fd_t, - pub stderr: __wasi_fd_t, + pub bid: __wasi_bid_t, + pub stdin: __wasi_option_fd_t, + pub stdout: __wasi_option_fd_t, + pub stderr: __wasi_option_fd_t, } #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] pub struct __wasi_busevent_exit_t { + pub bid: __wasi_bid_t, pub rval: __wasi_exitcode_t, } #[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] #[repr(C)] -pub struct __wasi_busevent_data_t { - pub ty: __wasi_busdatatype_t, - pub format: __wasi_busdataformat_t, +pub struct __wasi_busevent_call_t { + pub parent: __wasi_option_cid_t, pub cid: __wasi_cid_t, + pub format: __wasi_busdataformat_t, + pub topic_ptr: M::Offset, pub topic_len: M::Offset, + pub buf_ptr: M::Offset, + pub buf_len: M::Offset, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_busevent_result_t { + pub format: __wasi_busdataformat_t, + pub cid: __wasi_cid_t, + pub buf_ptr: M::Offset, pub buf_len: M::Offset, } @@ -70,12 +88,21 @@ pub struct __wasi_busevent_fault_t { pub err: __bus_errno_t, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueType)] +#[repr(C)] +pub struct __wasi_busevent_close_t { + pub cid: __wasi_cid_t, +} + #[derive(Copy, Clone)] #[repr(C)] pub union __wasi_busevent_u { + pub noop: u8, pub exit: __wasi_busevent_exit_t, - pub data: __wasi_busevent_data_t, + pub call: __wasi_busevent_call_t, + pub result: __wasi_busevent_result_t, pub fault: __wasi_busevent_fault_t, + pub close: __wasi_busevent_close_t, } #[derive(Copy, Clone)] diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 5ff475d8b1d..71375e7725a 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -47,7 +47,9 @@ pub use crate::state::{ WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD, }; pub use crate::syscalls::types; -pub use crate::utils::{get_wasi_version, get_wasi_versions, is_wasi_module, WasiVersion}; +pub use crate::utils::{ + get_wasi_version, get_wasi_versions, is_wasi_module, is_wasix_module, WasiVersion, +}; pub use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus}; #[deprecated(since = "2.1.0", note = "Please use `wasmer_vfs::FsError`")] pub use wasmer_vfs::FsError as WasiFsError; @@ -62,13 +64,13 @@ use std::ops::Deref; use thiserror::Error; use wasmer::{ imports, Function, Imports, LazyInit, Memory, Memory32, MemoryAccessError, MemorySize, Module, - Store, WasmerEnv, + Store, WasmerEnv, TypedFunction, }; pub use runtime::{ - PlugableRuntimeImplementation, WasiRuntimeImplementation, WasiThreadError, WasiTtyState, + PluggableRuntimeImplementation, WasiRuntimeImplementation, WasiThreadError, WasiTtyState, }; -use std::sync::{Arc, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::{mpsc, Arc, Mutex, RwLockReadGuard, RwLockWriteGuard}; use std::time::Duration; /// This is returned in `RuntimeError`. @@ -92,39 +94,201 @@ impl From for WasiThreadId { } impl Into for WasiThreadId { fn into(self) -> u32 { - self.0 + self.0 as u32 + } +} + +/// Represents the ID of a sub-process +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct WasiBusProcessId(u32); + +impl From for WasiBusProcessId { + fn from(id: u32) -> Self { + Self(id) + } +} +impl Into for WasiBusProcessId { + fn into(self) -> u32 { + self.0 as u32 } } -/// WASI processes can have multiple threads attached to the same environment -#[derive(Debug, Clone, WasmerEnv)] +#[cfg(target_family = "wasm")] +#[link(wasm_import_module = "__wbindgen_thread_xform__")] +extern "C" { + fn __wbindgen_thread_id() -> u32; +} + +#[derive(Debug, Clone)] pub struct WasiThread { /// ID of this thread + #[allow(dead_code)] id: WasiThreadId, - /// Provides access to the WASI environment - env: WasiEnv, + /// Signalers used to tell joiners that the thread has exited + exit: Arc>>>, + /// Event to wait on for the thread to join + join: Arc>>, +} + +impl WasiThread { + /// Waits for the thread to exit (false = timeout) + pub fn join(&self, timeout: Duration) -> bool { + let guard = self.join.lock().unwrap(); + match guard.recv_timeout(timeout) { + Ok(_) => true, + Err(mpsc::RecvTimeoutError::Disconnected) => true, + Err(mpsc::RecvTimeoutError::Timeout) => false, + } + } +} + +/// The environment provided to the WASI imports. +#[derive(Derivative, Clone, WasmerEnv)] +#[derivative(Debug)] +pub struct WasiEnv { + /// ID of this thread (zero is the main thread) + id: WasiThreadId, + /// Represents a reference to the memory #[wasmer(export)] memory: LazyInit, + /// If the module has it then map the thread start + #[derivative(Debug = "ignore")] + #[wasmer(export(optional = true, name = "_thread_start"))] + thread_start: LazyInit>, + #[derivative(Debug = "ignore")] + #[wasmer(export(optional = true, name = "_reactor_work"))] + reactor_work: LazyInit>, + #[derivative(Debug = "ignore")] + #[wasmer(export(optional = true, name = "_reactor_finish"))] + reactor_finish: LazyInit>, + #[derivative(Debug = "ignore")] + #[wasmer(export(optional = true, name = "_malloc"))] + malloc: LazyInit>, + #[derivative(Debug = "ignore")] + #[wasmer(export(optional = true, name = "_free"))] + free: LazyInit>, + /// Shared state of the WASI system. Manages all the data that the + /// executing WASI program can see. + pub state: Arc, + /// Implementation of the WASI runtime. + pub(crate) runtime: Arc, } -/// The WASI thread dereferences into the WASI environment -impl Deref for WasiThread { - type Target = WasiEnv; +impl WasiEnv { + pub fn new(state: WasiState) -> Self { + Self { + id: 0u32.into(), + state: Arc::new(state), + memory: LazyInit::new(), + thread_start: LazyInit::new(), + reactor_work: LazyInit::new(), + reactor_finish: LazyInit::new(), + malloc: LazyInit::new(), + free: LazyInit::new(), + runtime: Arc::new(PluggableRuntimeImplementation::default()), + } + } - fn deref(&self) -> &WasiEnv { - &self.env + /// Returns a copy of the current runtime implementation for this environment + pub fn runtime<'a>(&'a self) -> &'a (dyn WasiRuntimeImplementation) { + self.runtime.deref() } -} -impl WasiThread { - /// Returns the unique ID of this thread - pub fn thread_id(&self) -> WasiThreadId { + /// Overrides the runtime implementation for this environment + pub fn set_runtime(&mut self, runtime: R) + where + R: WasiRuntimeImplementation + Send + Sync + 'static, + { + self.runtime = Arc::new(runtime); + } + + /// Returns the current thread ID + pub fn current_thread_id(&self) -> WasiThreadId { self.id } + /// Creates a new thread only this wasi environment + pub fn new_thread(&self) -> WasiThread { + let (tx, rx) = mpsc::channel(); + + let mut guard = self.state.threading.lock().unwrap(); + + guard.thread_seed += 1; + let next_id: WasiThreadId = guard.thread_seed.into(); + + let thread = WasiThread { + id: next_id, + exit: Arc::new(Mutex::new(Some(tx))), + join: Arc::new(Mutex::new(rx)), + }; + + guard.threads.insert(thread.id, thread.clone()); + thread + } + + /// Get the WASI state + /// + /// Be careful when using this in host functions that call into Wasm: + /// if the lock is held and the Wasm calls into a host function that tries + /// to lock this mutex, the program will deadlock. + pub fn state(&self) -> &WasiState { + self.state.deref() + } + + /// Get a reference to the memory + pub fn memory(&self) -> &Memory { + self.memory + .get_ref() + .expect("Memory should be set on `WasiEnv` first") + } + + /// Copy the lazy reference so that when it's initialized during the + /// export phase, all the other references get a copy of it + pub fn memory_clone(&self) -> LazyInit { + self.memory.clone() + } + + /// Get an `Imports` for a specific version of WASI detected in the module. + pub fn import_object(&mut self, module: &Module) -> Result { + let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?; + Ok(generate_import_object_from_env( + module.store(), + self.clone(), + wasi_version, + )) + } + + /// Like `import_object` but containing all the WASI versions detected in + /// the module. + pub fn import_object_for_all_wasi_versions( + &mut self, + module: &Module, + ) -> Result { + let wasi_versions = + get_wasi_versions(module, false).ok_or(WasiError::UnknownWasiVersion)?; + + let mut resolver = Imports::new(); + for version in wasi_versions.iter() { + let new_import_object = + generate_import_object_from_env(module.store(), self.clone(), *version); + for ((n, m), e) in new_import_object.into_iter() { + resolver.define(&n, &m, e); + } + } + + if is_wasix_module(module) { + self.state + .fs + .is_wasix + .store(true, std::sync::atomic::Ordering::Release); + } + + Ok(resolver) + } + // Yields execution pub fn yield_now(&self) -> Result<(), WasiError> { - self.env.runtime.yield_now(self.id)?; + self.runtime.yield_now(self.id)?; Ok(()) } @@ -158,26 +322,13 @@ impl WasiThread { /// Accesses the virtual networking implementation pub fn net<'a>(&'a self) -> &'a (dyn VirtualNetworking) { - self.env.runtime.networking() + self.runtime.networking() } /// Accesses the virtual bus implementation pub fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { - self.env.runtime.bus() - } - - /// Get a reference to the memory - pub fn memory(&self) -> &Memory { - self.memory_ref() - .expect("Memory should be set on `WasiEnv` first") + self.runtime.bus() } - - // Copy the lazy reference so that when its initialized during the - // export phase that all the other references get a copy of it - pub fn memory_clone(&self) -> LazyInit { - self.memory.clone() - } - pub(crate) fn get_memory_and_wasi_state(&self, _mem_index: u32) -> (&Memory, &WasiState) { let memory = self.memory(); let state = self.state.deref(); @@ -203,460 +354,361 @@ impl WasiThread { let inodes = state.inodes.write().unwrap(); (memory, state, inodes) } - - /// Get an `Imports` for a specific version of WASI detected in the module. - pub fn import_object(&mut self, module: &Module) -> Result { - let wasi_version = get_wasi_version(module, false).ok_or(WasiError::UnknownWasiVersion)?; - Ok(generate_import_object_from_thread( - module.store(), - self.clone(), - wasi_version, - )) - } - - /// Like `import_object` but containing all the WASI versions detected in - /// the module. - pub fn import_object_for_all_wasi_versions( - &mut self, - module: &Module, - ) -> Result { - let wasi_versions = - get_wasi_versions(module, false).ok_or(WasiError::UnknownWasiVersion)?; - - let mut resolver = Imports::new(); - for version in wasi_versions.iter() { - let new_import_object = - generate_import_object_from_thread(module.store(), self.clone(), *version); - for ((n, m), e) in new_import_object.into_iter() { - resolver.define(&n, &m, e); - } - } - Ok(resolver) - } -} - -/// The environment provided to the WASI imports. -#[derive(Derivative, Clone)] -#[derivative(Debug)] -pub struct WasiEnv { - /// Represents a reference to the memory - memory: LazyInit, - /// Shared state of the WASI system. Manages all the data that the - /// executing WASI program can see. - pub state: Arc, - /// Implementation of the WASI runtime. - pub(crate) runtime: Arc, -} - -impl WasiEnv { - pub fn new(state: WasiState) -> Self { - Self { - state: Arc::new(state), - memory: LazyInit::new(), - runtime: Arc::new(PlugableRuntimeImplementation::default()), - } - } - - /// Returns a copy of the current runtime implementation for this environment - pub fn runtime<'a>(&'a self) -> &'a (dyn WasiRuntimeImplementation) { - self.runtime.deref() - } - - /// Overrides the runtime implementation for this environment - pub fn set_runtime(&mut self, runtime: R) - where - R: WasiRuntimeImplementation + Send + Sync + 'static, - { - self.runtime = Arc::new(runtime); - } - - /// Creates a new thread only this wasi environment - pub fn new_thread(&self) -> WasiThread { - WasiThread { - id: self.runtime.thread_generate_id(), - env: self.clone(), - memory: self.memory_clone(), - } - } - - /// Get the WASI state - /// - /// Be careful when using this in host functions that call into Wasm: - /// if the lock is held and the Wasm calls into a host function that tries - /// to lock this mutex, the program will deadlock. - pub fn state(&self) -> &WasiState { - self.state.deref() - } - - /// Get a reference to the memory - pub fn memory(&self) -> &Memory { - self.memory - .get_ref() - .expect("Memory should be set on `WasiEnv` first") - } - - /// Copy the lazy reference so that when it's initialized during the - /// export phase, all the other references get a copy of it - pub fn memory_clone(&self) -> LazyInit { - self.memory.clone() - } } /// Create an [`Imports`] with an existing [`WasiEnv`]. `WasiEnv` /// needs a [`WasiState`], that can be constructed from a /// [`WasiStateBuilder`](state::WasiStateBuilder). -pub fn generate_import_object_from_thread( +pub fn generate_import_object_from_env( store: &Store, - thread: WasiThread, + env: WasiEnv, version: WasiVersion, ) -> Imports { match version { - WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, thread), - WasiVersion::Wasix32v1 => generate_import_object_wasix32_v1(store, thread), - WasiVersion::Wasix64v1 => generate_import_object_wasix64_v1(store, thread), + WasiVersion::Snapshot0 => generate_import_object_snapshot0(store, env), + WasiVersion::Wasix32v1 => generate_import_object_wasix32_v1(store, env), + WasiVersion::Wasix64v1 => generate_import_object_wasix64_v1(store, env), WasiVersion::Snapshot1 | WasiVersion::Latest => { - generate_import_object_snapshot1(store, thread) + generate_import_object_snapshot1(store, env) } } } /// Combines a state generating function with the import list for legacy WASI -fn generate_import_object_snapshot0(store: &Store, thread: WasiThread) -> Imports { +fn generate_import_object_snapshot0(store: &Store, env: WasiEnv) -> Imports { use self::wasi::*; imports! { "wasi_unstable" => { - "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), - "args_sizes_get" => Function::new_native_with_env(store, thread.clone(), args_sizes_get), - "clock_res_get" => Function::new_native_with_env(store, thread.clone(), clock_res_get), - "clock_time_get" => Function::new_native_with_env(store, thread.clone(), clock_time_get), - "environ_get" => Function::new_native_with_env(store, thread.clone(), environ_get), - "environ_sizes_get" => Function::new_native_with_env(store, thread.clone(), environ_sizes_get), - "fd_advise" => Function::new_native_with_env(store, thread.clone(), fd_advise), - "fd_allocate" => Function::new_native_with_env(store, thread.clone(), fd_allocate), - "fd_close" => Function::new_native_with_env(store, thread.clone(), fd_close), - "fd_datasync" => Function::new_native_with_env(store, thread.clone(), fd_datasync), - "fd_fdstat_get" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_native_with_env(store, thread.clone(), legacy::snapshot0::fd_filestat_get), - "fd_filestat_set_size" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_times), - "fd_pread" => Function::new_native_with_env(store, thread.clone(), fd_pread), - "fd_prestat_get" => Function::new_native_with_env(store, thread.clone(), fd_prestat_get), - "fd_prestat_dir_name" => Function::new_native_with_env(store, thread.clone(), fd_prestat_dir_name), - "fd_pwrite" => Function::new_native_with_env(store, thread.clone(), fd_pwrite), - "fd_read" => Function::new_native_with_env(store, thread.clone(), fd_read), - "fd_readdir" => Function::new_native_with_env(store, thread.clone(), fd_readdir), - "fd_renumber" => Function::new_native_with_env(store, thread.clone(), fd_renumber), - "fd_seek" => Function::new_native_with_env(store, thread.clone(), legacy::snapshot0::fd_seek), - "fd_sync" => Function::new_native_with_env(store, thread.clone(), fd_sync), - "fd_tell" => Function::new_native_with_env(store, thread.clone(), fd_tell), - "fd_write" => Function::new_native_with_env(store, thread.clone(), fd_write), - "path_create_directory" => Function::new_native_with_env(store, thread.clone(), path_create_directory), - "path_filestat_get" => Function::new_native_with_env(store, thread.clone(), legacy::snapshot0::path_filestat_get), - "path_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), path_filestat_set_times), - "path_link" => Function::new_native_with_env(store, thread.clone(), path_link), - "path_open" => Function::new_native_with_env(store, thread.clone(), path_open), - "path_readlink" => Function::new_native_with_env(store, thread.clone(), path_readlink), - "path_remove_directory" => Function::new_native_with_env(store, thread.clone(), path_remove_directory), - "path_rename" => Function::new_native_with_env(store, thread.clone(), path_rename), - "path_symlink" => Function::new_native_with_env(store, thread.clone(), path_symlink), - "path_unlink_file" => Function::new_native_with_env(store, thread.clone(), path_unlink_file), - "poll_oneoff" => Function::new_native_with_env(store, thread.clone(), legacy::snapshot0::poll_oneoff), - "proc_exit" => Function::new_native_with_env(store, thread.clone(), proc_exit), - "proc_raise" => Function::new_native_with_env(store, thread.clone(), proc_raise), - "random_get" => Function::new_native_with_env(store, thread.clone(), random_get), - "sched_yield" => Function::new_native_with_env(store, thread.clone(), sched_yield), - "sock_recv" => Function::new_native_with_env(store, thread.clone(), sock_recv), - "sock_send" => Function::new_native_with_env(store, thread.clone(), sock_send), - "sock_shutdown" => Function::new_native_with_env(store, thread, sock_shutdown), + "args_get" => Function::new_native_with_env(store, env.clone(), args_get), + "args_sizes_get" => Function::new_native_with_env(store, env.clone(), args_sizes_get), + "clock_res_get" => Function::new_native_with_env(store, env.clone(), clock_res_get), + "clock_time_get" => Function::new_native_with_env(store, env.clone(), clock_time_get), + "environ_get" => Function::new_native_with_env(store, env.clone(), environ_get), + "environ_sizes_get" => Function::new_native_with_env(store, env.clone(), environ_sizes_get), + "fd_advise" => Function::new_native_with_env(store, env.clone(), fd_advise), + "fd_allocate" => Function::new_native_with_env(store, env.clone(), fd_allocate), + "fd_close" => Function::new_native_with_env(store, env.clone(), fd_close), + "fd_datasync" => Function::new_native_with_env(store, env.clone(), fd_datasync), + "fd_fdstat_get" => Function::new_native_with_env(store, env.clone(), fd_fdstat_get), + "fd_fdstat_set_flags" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native_with_env(store, env.clone(), legacy::snapshot0::fd_filestat_get), + "fd_filestat_set_size" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_times), + "fd_pread" => Function::new_native_with_env(store, env.clone(), fd_pread), + "fd_prestat_get" => Function::new_native_with_env(store, env.clone(), fd_prestat_get), + "fd_prestat_dir_name" => Function::new_native_with_env(store, env.clone(), fd_prestat_dir_name), + "fd_pwrite" => Function::new_native_with_env(store, env.clone(), fd_pwrite), + "fd_read" => Function::new_native_with_env(store, env.clone(), fd_read), + "fd_readdir" => Function::new_native_with_env(store, env.clone(), fd_readdir), + "fd_renumber" => Function::new_native_with_env(store, env.clone(), fd_renumber), + "fd_seek" => Function::new_native_with_env(store, env.clone(), legacy::snapshot0::fd_seek), + "fd_sync" => Function::new_native_with_env(store, env.clone(), fd_sync), + "fd_tell" => Function::new_native_with_env(store, env.clone(), fd_tell), + "fd_write" => Function::new_native_with_env(store, env.clone(), fd_write), + "path_create_directory" => Function::new_native_with_env(store, env.clone(), path_create_directory), + "path_filestat_get" => Function::new_native_with_env(store, env.clone(), legacy::snapshot0::path_filestat_get), + "path_filestat_set_times" => Function::new_native_with_env(store, env.clone(), path_filestat_set_times), + "path_link" => Function::new_native_with_env(store, env.clone(), path_link), + "path_open" => Function::new_native_with_env(store, env.clone(), path_open), + "path_readlink" => Function::new_native_with_env(store, env.clone(), path_readlink), + "path_remove_directory" => Function::new_native_with_env(store, env.clone(), path_remove_directory), + "path_rename" => Function::new_native_with_env(store, env.clone(), path_rename), + "path_symlink" => Function::new_native_with_env(store, env.clone(), path_symlink), + "path_unlink_file" => Function::new_native_with_env(store, env.clone(), path_unlink_file), + "poll_oneoff" => Function::new_native_with_env(store, env.clone(), legacy::snapshot0::poll_oneoff), + "proc_exit" => Function::new_native_with_env(store, env.clone(), proc_exit), + "proc_raise" => Function::new_native_with_env(store, env.clone(), proc_raise), + "random_get" => Function::new_native_with_env(store, env.clone(), random_get), + "sched_yield" => Function::new_native_with_env(store, env.clone(), sched_yield), + "sock_recv" => Function::new_native_with_env(store, env.clone(), sock_recv), + "sock_send" => Function::new_native_with_env(store, env.clone(), sock_send), + "sock_shutdown" => Function::new_native_with_env(store, env, sock_shutdown), }, } } /// Combines a state generating function with the import list for snapshot 1 -fn generate_import_object_snapshot1(store: &Store, thread: WasiThread) -> Imports { +fn generate_import_object_snapshot1(store: &Store, env: WasiEnv) -> Imports { use self::wasi::*; imports! { "wasi_snapshot_preview1" => { - "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), - "args_sizes_get" => Function::new_native_with_env(store, thread.clone(), args_sizes_get), - "clock_res_get" => Function::new_native_with_env(store, thread.clone(), clock_res_get), - "clock_time_get" => Function::new_native_with_env(store, thread.clone(), clock_time_get), - "environ_get" => Function::new_native_with_env(store, thread.clone(), environ_get), - "environ_sizes_get" => Function::new_native_with_env(store, thread.clone(), environ_sizes_get), - "fd_advise" => Function::new_native_with_env(store, thread.clone(), fd_advise), - "fd_allocate" => Function::new_native_with_env(store, thread.clone(), fd_allocate), - "fd_close" => Function::new_native_with_env(store, thread.clone(), fd_close), - "fd_datasync" => Function::new_native_with_env(store, thread.clone(), fd_datasync), - "fd_fdstat_get" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_native_with_env(store, thread.clone(), fd_filestat_get), - "fd_filestat_set_size" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_times), - "fd_pread" => Function::new_native_with_env(store, thread.clone(), fd_pread), - "fd_prestat_get" => Function::new_native_with_env(store, thread.clone(), fd_prestat_get), - "fd_prestat_dir_name" => Function::new_native_with_env(store, thread.clone(), fd_prestat_dir_name), - "fd_pwrite" => Function::new_native_with_env(store, thread.clone(), fd_pwrite), - "fd_read" => Function::new_native_with_env(store, thread.clone(), fd_read), - "fd_readdir" => Function::new_native_with_env(store, thread.clone(), fd_readdir), - "fd_renumber" => Function::new_native_with_env(store, thread.clone(), fd_renumber), - "fd_seek" => Function::new_native_with_env(store, thread.clone(), fd_seek), - "fd_sync" => Function::new_native_with_env(store, thread.clone(), fd_sync), - "fd_tell" => Function::new_native_with_env(store, thread.clone(), fd_tell), - "fd_write" => Function::new_native_with_env(store, thread.clone(), fd_write), - "path_create_directory" => Function::new_native_with_env(store, thread.clone(), path_create_directory), - "path_filestat_get" => Function::new_native_with_env(store, thread.clone(), path_filestat_get), - "path_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), path_filestat_set_times), - "path_link" => Function::new_native_with_env(store, thread.clone(), path_link), - "path_open" => Function::new_native_with_env(store, thread.clone(), path_open), - "path_readlink" => Function::new_native_with_env(store, thread.clone(), path_readlink), - "path_remove_directory" => Function::new_native_with_env(store, thread.clone(), path_remove_directory), - "path_rename" => Function::new_native_with_env(store, thread.clone(), path_rename), - "path_symlink" => Function::new_native_with_env(store, thread.clone(), path_symlink), - "path_unlink_file" => Function::new_native_with_env(store, thread.clone(), path_unlink_file), - "poll_oneoff" => Function::new_native_with_env(store, thread.clone(), poll_oneoff), - "proc_exit" => Function::new_native_with_env(store, thread.clone(), proc_exit), - "proc_raise" => Function::new_native_with_env(store, thread.clone(), proc_raise), - "random_get" => Function::new_native_with_env(store, thread.clone(), random_get), - "sched_yield" => Function::new_native_with_env(store, thread.clone(), sched_yield), - "sock_recv" => Function::new_native_with_env(store, thread.clone(), sock_recv), - "sock_send" => Function::new_native_with_env(store, thread.clone(), sock_send), - "sock_shutdown" => Function::new_native_with_env(store, thread, sock_shutdown), + "args_get" => Function::new_native_with_env(store, env.clone(), args_get), + "args_sizes_get" => Function::new_native_with_env(store, env.clone(), args_sizes_get), + "clock_res_get" => Function::new_native_with_env(store, env.clone(), clock_res_get), + "clock_time_get" => Function::new_native_with_env(store, env.clone(), clock_time_get), + "environ_get" => Function::new_native_with_env(store, env.clone(), environ_get), + "environ_sizes_get" => Function::new_native_with_env(store, env.clone(), environ_sizes_get), + "fd_advise" => Function::new_native_with_env(store, env.clone(), fd_advise), + "fd_allocate" => Function::new_native_with_env(store, env.clone(), fd_allocate), + "fd_close" => Function::new_native_with_env(store, env.clone(), fd_close), + "fd_datasync" => Function::new_native_with_env(store, env.clone(), fd_datasync), + "fd_fdstat_get" => Function::new_native_with_env(store, env.clone(), fd_fdstat_get), + "fd_fdstat_set_flags" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native_with_env(store, env.clone(), fd_filestat_get), + "fd_filestat_set_size" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_times), + "fd_pread" => Function::new_native_with_env(store, env.clone(), fd_pread), + "fd_prestat_get" => Function::new_native_with_env(store, env.clone(), fd_prestat_get), + "fd_prestat_dir_name" => Function::new_native_with_env(store, env.clone(), fd_prestat_dir_name), + "fd_pwrite" => Function::new_native_with_env(store, env.clone(), fd_pwrite), + "fd_read" => Function::new_native_with_env(store, env.clone(), fd_read), + "fd_readdir" => Function::new_native_with_env(store, env.clone(), fd_readdir), + "fd_renumber" => Function::new_native_with_env(store, env.clone(), fd_renumber), + "fd_seek" => Function::new_native_with_env(store, env.clone(), fd_seek), + "fd_sync" => Function::new_native_with_env(store, env.clone(), fd_sync), + "fd_tell" => Function::new_native_with_env(store, env.clone(), fd_tell), + "fd_write" => Function::new_native_with_env(store, env.clone(), fd_write), + "path_create_directory" => Function::new_native_with_env(store, env.clone(), path_create_directory), + "path_filestat_get" => Function::new_native_with_env(store, env.clone(), path_filestat_get), + "path_filestat_set_times" => Function::new_native_with_env(store, env.clone(), path_filestat_set_times), + "path_link" => Function::new_native_with_env(store, env.clone(), path_link), + "path_open" => Function::new_native_with_env(store, env.clone(), path_open), + "path_readlink" => Function::new_native_with_env(store, env.clone(), path_readlink), + "path_remove_directory" => Function::new_native_with_env(store, env.clone(), path_remove_directory), + "path_rename" => Function::new_native_with_env(store, env.clone(), path_rename), + "path_symlink" => Function::new_native_with_env(store, env.clone(), path_symlink), + "path_unlink_file" => Function::new_native_with_env(store, env.clone(), path_unlink_file), + "poll_oneoff" => Function::new_native_with_env(store, env.clone(), poll_oneoff), + "proc_exit" => Function::new_native_with_env(store, env.clone(), proc_exit), + "proc_raise" => Function::new_native_with_env(store, env.clone(), proc_raise), + "random_get" => Function::new_native_with_env(store, env.clone(), random_get), + "sched_yield" => Function::new_native_with_env(store, env.clone(), sched_yield), + "sock_recv" => Function::new_native_with_env(store, env.clone(), sock_recv), + "sock_send" => Function::new_native_with_env(store, env.clone(), sock_send), + "sock_shutdown" => Function::new_native_with_env(store, env, sock_shutdown), } } } /// Combines a state generating function with the import list for snapshot 1 -fn generate_import_object_wasix32_v1(store: &Store, thread: WasiThread) -> Imports { +fn generate_import_object_wasix32_v1(store: &Store, env: WasiEnv) -> Imports { use self::wasix32::*; imports! { "wasix_32v1" => { - "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), - "args_sizes_get" => Function::new_native_with_env(store, thread.clone(), args_sizes_get), - "clock_res_get" => Function::new_native_with_env(store, thread.clone(), clock_res_get), - "clock_time_get" => Function::new_native_with_env(store, thread.clone(), clock_time_get), - "environ_get" => Function::new_native_with_env(store, thread.clone(), environ_get), - "environ_sizes_get" => Function::new_native_with_env(store, thread.clone(), environ_sizes_get), - "fd_advise" => Function::new_native_with_env(store, thread.clone(), fd_advise), - "fd_allocate" => Function::new_native_with_env(store, thread.clone(), fd_allocate), - "fd_close" => Function::new_native_with_env(store, thread.clone(), fd_close), - "fd_datasync" => Function::new_native_with_env(store, thread.clone(), fd_datasync), - "fd_fdstat_get" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_native_with_env(store, thread.clone(), fd_filestat_get), - "fd_filestat_set_size" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_times), - "fd_pread" => Function::new_native_with_env(store, thread.clone(), fd_pread), - "fd_prestat_get" => Function::new_native_with_env(store, thread.clone(), fd_prestat_get), - "fd_prestat_dir_name" => Function::new_native_with_env(store, thread.clone(), fd_prestat_dir_name), - "fd_pwrite" => Function::new_native_with_env(store, thread.clone(), fd_pwrite), - "fd_read" => Function::new_native_with_env(store, thread.clone(), fd_read), - "fd_readdir" => Function::new_native_with_env(store, thread.clone(), fd_readdir), - "fd_renumber" => Function::new_native_with_env(store, thread.clone(), fd_renumber), - "fd_dup" => Function::new_native_with_env(store, thread.clone(), fd_dup), - "fd_event" => Function::new_native_with_env(store, thread.clone(), fd_event), - "fd_seek" => Function::new_native_with_env(store, thread.clone(), fd_seek), - "fd_sync" => Function::new_native_with_env(store, thread.clone(), fd_sync), - "fd_tell" => Function::new_native_with_env(store, thread.clone(), fd_tell), - "fd_write" => Function::new_native_with_env(store, thread.clone(), fd_write), - "fd_pipe" => Function::new_native_with_env(store, thread.clone(), fd_pipe), - "path_create_directory" => Function::new_native_with_env(store, thread.clone(), path_create_directory), - "path_filestat_get" => Function::new_native_with_env(store, thread.clone(), path_filestat_get), - "path_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), path_filestat_set_times), - "path_link" => Function::new_native_with_env(store, thread.clone(), path_link), - "path_open" => Function::new_native_with_env(store, thread.clone(), path_open), - "path_readlink" => Function::new_native_with_env(store, thread.clone(), path_readlink), - "path_remove_directory" => Function::new_native_with_env(store, thread.clone(), path_remove_directory), - "path_rename" => Function::new_native_with_env(store, thread.clone(), path_rename), - "path_symlink" => Function::new_native_with_env(store, thread.clone(), path_symlink), - "path_unlink_file" => Function::new_native_with_env(store, thread.clone(), path_unlink_file), - "poll_oneoff" => Function::new_native_with_env(store, thread.clone(), poll_oneoff), - "proc_exit" => Function::new_native_with_env(store, thread.clone(), proc_exit), - "proc_raise" => Function::new_native_with_env(store, thread.clone(), proc_raise), - "random_get" => Function::new_native_with_env(store, thread.clone(), random_get), - "tty_get" => Function::new_native_with_env(store, thread.clone(), tty_get), - "tty_set" => Function::new_native_with_env(store, thread.clone(), tty_set), - "getcwd" => Function::new_native_with_env(store, thread.clone(), getcwd), - "chdir" => Function::new_native_with_env(store, thread.clone(), chdir), - "thread_spawn" => Function::new_native_with_env(store, thread.clone(), thread_spawn), - "thread_sleep" => Function::new_native_with_env(store, thread.clone(), thread_sleep), - "thread_id" => Function::new_native_with_env(store, thread.clone(), thread_id), - "thread_join" => Function::new_native_with_env(store, thread.clone(), thread_join), - "thread_parallelism" => Function::new_native_with_env(store, thread.clone(), thread_parallelism), - "thread_exit" => Function::new_native_with_env(store, thread.clone(), thread_exit), - "sched_yield" => Function::new_native_with_env(store, thread.clone(), sched_yield), - "getpid" => Function::new_native_with_env(store, thread.clone(), getpid), - "bus_spawn_local" => Function::new_native_with_env(store, thread.clone(), bus_spawn_local), - "bus_spawn_remote" => Function::new_native_with_env(store, thread.clone(), bus_spawn_remote), - "bus_close" => Function::new_native_with_env(store, thread.clone(), bus_close), - "bus_invoke" => Function::new_native_with_env(store, thread.clone(), bus_invoke), - "bus_fault" => Function::new_native_with_env(store, thread.clone(), bus_fault), - "bus_drop" => Function::new_native_with_env(store, thread.clone(), bus_drop), - "bus_reply" => Function::new_native_with_env(store, thread.clone(), bus_reply), - "bus_callback" => Function::new_native_with_env(store, thread.clone(), bus_callback), - "bus_listen" => Function::new_native_with_env(store, thread.clone(), bus_listen), - "bus_poll" => Function::new_native_with_env(store, thread.clone(), bus_poll), - "bus_poll_data" => Function::new_native_with_env(store, thread.clone(), bus_poll_data), - "ws_connect" => Function::new_native_with_env(store, thread.clone(), ws_connect), - "http_request" => Function::new_native_with_env(store, thread.clone(), http_request), - "http_status" => Function::new_native_with_env(store, thread.clone(), http_status), - "port_bridge" => Function::new_native_with_env(store, thread.clone(), port_bridge), - "port_unbridge" => Function::new_native_with_env(store, thread.clone(), port_unbridge), - "port_dhcp_acquire" => Function::new_native_with_env(store, thread.clone(), port_dhcp_acquire), - "port_addr_add" => Function::new_native_with_env(store, thread.clone(), port_addr_add), - "port_addr_remove" => Function::new_native_with_env(store, thread.clone(), port_addr_remove), - "port_addr_clear" => Function::new_native_with_env(store, thread.clone(), port_addr_clear), - "port_addr_list" => Function::new_native_with_env(store, thread.clone(), port_addr_list), - "port_mac" => Function::new_native_with_env(store, thread.clone(), port_mac), - "port_gateway_set" => Function::new_native_with_env(store, thread.clone(), port_gateway_set), - "port_route_add" => Function::new_native_with_env(store, thread.clone(), port_route_add), - "port_route_remove" => Function::new_native_with_env(store, thread.clone(), port_route_remove), - "port_route_clear" => Function::new_native_with_env(store, thread.clone(), port_route_clear), - "port_route_list" => Function::new_native_with_env(store, thread.clone(), port_route_list), - "sock_status" => Function::new_native_with_env(store, thread.clone(), sock_status), - "sock_addr_local" => Function::new_native_with_env(store, thread.clone(), sock_addr_local), - "sock_addr_peer" => Function::new_native_with_env(store, thread.clone(), sock_addr_peer), - "sock_open" => Function::new_native_with_env(store, thread.clone(), sock_open), - "sock_set_opt_flag" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_flag), - "sock_get_opt_flag" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_flag), - "sock_set_opt_time" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_time), - "sock_get_opt_time" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_time), - "sock_set_opt_size" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_size), - "sock_get_opt_size" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_size), - "sock_join_multicast_v4" => Function::new_native_with_env(store, thread.clone(), sock_join_multicast_v4), - "sock_leave_multicast_v4" => Function::new_native_with_env(store, thread.clone(), sock_leave_multicast_v4), - "sock_join_multicast_v6" => Function::new_native_with_env(store, thread.clone(), sock_join_multicast_v6), - "sock_leave_multicast_v6" => Function::new_native_with_env(store, thread.clone(), sock_leave_multicast_v6), - "sock_bind" => Function::new_native_with_env(store, thread.clone(), sock_bind), - "sock_listen" => Function::new_native_with_env(store, thread.clone(), sock_listen), - "sock_accept" => Function::new_native_with_env(store, thread.clone(), sock_accept), - "sock_connect" => Function::new_native_with_env(store, thread.clone(), sock_connect), - "sock_recv" => Function::new_native_with_env(store, thread.clone(), sock_recv), - "sock_recv_from" => Function::new_native_with_env(store, thread.clone(), sock_recv_from), - "sock_send" => Function::new_native_with_env(store, thread.clone(), sock_send), - "sock_send_to" => Function::new_native_with_env(store, thread.clone(), sock_send_to), - "sock_send_file" => Function::new_native_with_env(store, thread.clone(), sock_send_file), - "sock_shutdown" => Function::new_native_with_env(store, thread.clone(), sock_shutdown), - "resolve" => Function::new_native_with_env(store, thread.clone(), resolve), + "args_get" => Function::new_native_with_env(store, env.clone(), args_get), + "args_sizes_get" => Function::new_native_with_env(store, env.clone(), args_sizes_get), + "clock_res_get" => Function::new_native_with_env(store, env.clone(), clock_res_get), + "clock_time_get" => Function::new_native_with_env(store, env.clone(), clock_time_get), + "environ_get" => Function::new_native_with_env(store, env.clone(), environ_get), + "environ_sizes_get" => Function::new_native_with_env(store, env.clone(), environ_sizes_get), + "fd_advise" => Function::new_native_with_env(store, env.clone(), fd_advise), + "fd_allocate" => Function::new_native_with_env(store, env.clone(), fd_allocate), + "fd_close" => Function::new_native_with_env(store, env.clone(), fd_close), + "fd_datasync" => Function::new_native_with_env(store, env.clone(), fd_datasync), + "fd_fdstat_get" => Function::new_native_with_env(store, env.clone(), fd_fdstat_get), + "fd_fdstat_set_flags" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native_with_env(store, env.clone(), fd_filestat_get), + "fd_filestat_set_size" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_times), + "fd_pread" => Function::new_native_with_env(store, env.clone(), fd_pread), + "fd_prestat_get" => Function::new_native_with_env(store, env.clone(), fd_prestat_get), + "fd_prestat_dir_name" => Function::new_native_with_env(store, env.clone(), fd_prestat_dir_name), + "fd_pwrite" => Function::new_native_with_env(store, env.clone(), fd_pwrite), + "fd_read" => Function::new_native_with_env(store, env.clone(), fd_read), + "fd_readdir" => Function::new_native_with_env(store, env.clone(), fd_readdir), + "fd_renumber" => Function::new_native_with_env(store, env.clone(), fd_renumber), + "fd_dup" => Function::new_native_with_env(store, env.clone(), fd_dup), + "fd_event" => Function::new_native_with_env(store, env.clone(), fd_event), + "fd_seek" => Function::new_native_with_env(store, env.clone(), fd_seek), + "fd_sync" => Function::new_native_with_env(store, env.clone(), fd_sync), + "fd_tell" => Function::new_native_with_env(store, env.clone(), fd_tell), + "fd_write" => Function::new_native_with_env(store, env.clone(), fd_write), + "fd_pipe" => Function::new_native_with_env(store, env.clone(), fd_pipe), + "path_create_directory" => Function::new_native_with_env(store, env.clone(), path_create_directory), + "path_filestat_get" => Function::new_native_with_env(store, env.clone(), path_filestat_get), + "path_filestat_set_times" => Function::new_native_with_env(store, env.clone(), path_filestat_set_times), + "path_link" => Function::new_native_with_env(store, env.clone(), path_link), + "path_open" => Function::new_native_with_env(store, env.clone(), path_open), + "path_readlink" => Function::new_native_with_env(store, env.clone(), path_readlink), + "path_remove_directory" => Function::new_native_with_env(store, env.clone(), path_remove_directory), + "path_rename" => Function::new_native_with_env(store, env.clone(), path_rename), + "path_symlink" => Function::new_native_with_env(store, env.clone(), path_symlink), + "path_unlink_file" => Function::new_native_with_env(store, env.clone(), path_unlink_file), + "poll_oneoff" => Function::new_native_with_env(store, env.clone(), poll_oneoff), + "proc_exit" => Function::new_native_with_env(store, env.clone(), proc_exit), + "proc_raise" => Function::new_native_with_env(store, env.clone(), proc_raise), + "random_get" => Function::new_native_with_env(store, env.clone(), random_get), + "tty_get" => Function::new_native_with_env(store, env.clone(), tty_get), + "tty_set" => Function::new_native_with_env(store, env.clone(), tty_set), + "getcwd" => Function::new_native_with_env(store, env.clone(), getcwd), + "chdir" => Function::new_native_with_env(store, env.clone(), chdir), + "thread_spawn" => Function::new_native_with_env(store, env.clone(), thread_spawn), + "thread_sleep" => Function::new_native_with_env(store, env.clone(), thread_sleep), + "thread_id" => Function::new_native_with_env(store, env.clone(), thread_id), + "thread_join" => Function::new_native_with_env(store, env.clone(), thread_join), + "thread_parallelism" => Function::new_native_with_env(store, env.clone(), thread_parallelism), + "thread_exit" => Function::new_native_with_env(store, env.clone(), thread_exit), + "sched_yield" => Function::new_native_with_env(store, env.clone(), sched_yield), + "getpid" => Function::new_native_with_env(store, env.clone(), getpid), + "process_spawn" => Function::new_native_with_env(store, env.clone(), process_spawn), + "bus_open_local" => Function::new_native_with_env(store, env.clone(), bus_open_local), + "bus_open_remote" => Function::new_native_with_env(store, env.clone(), bus_open_remote), + "bus_close" => Function::new_native_with_env(store, env.clone(), bus_close), + "bus_call" => Function::new_native_with_env(store, env.clone(), bus_call), + "bus_subcall" => Function::new_native_with_env(store, env.clone(), bus_subcall), + "bus_poll" => Function::new_native_with_env(store, env.clone(), bus_poll), + "call_reply" => Function::new_native_with_env(store, env.clone(), call_reply), + "call_fault" => Function::new_native_with_env(store, env.clone(), call_fault), + "call_close" => Function::new_native_with_env(store, env.clone(), call_close), + "ws_connect" => Function::new_native_with_env(store, env.clone(), ws_connect), + "http_request" => Function::new_native_with_env(store, env.clone(), http_request), + "http_status" => Function::new_native_with_env(store, env.clone(), http_status), + "port_bridge" => Function::new_native_with_env(store, env.clone(), port_bridge), + "port_unbridge" => Function::new_native_with_env(store, env.clone(), port_unbridge), + "port_dhcp_acquire" => Function::new_native_with_env(store, env.clone(), port_dhcp_acquire), + "port_addr_add" => Function::new_native_with_env(store, env.clone(), port_addr_add), + "port_addr_remove" => Function::new_native_with_env(store, env.clone(), port_addr_remove), + "port_addr_clear" => Function::new_native_with_env(store, env.clone(), port_addr_clear), + "port_addr_list" => Function::new_native_with_env(store, env.clone(), port_addr_list), + "port_mac" => Function::new_native_with_env(store, env.clone(), port_mac), + "port_gateway_set" => Function::new_native_with_env(store, env.clone(), port_gateway_set), + "port_route_add" => Function::new_native_with_env(store, env.clone(), port_route_add), + "port_route_remove" => Function::new_native_with_env(store, env.clone(), port_route_remove), + "port_route_clear" => Function::new_native_with_env(store, env.clone(), port_route_clear), + "port_route_list" => Function::new_native_with_env(store, env.clone(), port_route_list), + "sock_status" => Function::new_native_with_env(store, env.clone(), sock_status), + "sock_addr_local" => Function::new_native_with_env(store, env.clone(), sock_addr_local), + "sock_addr_peer" => Function::new_native_with_env(store, env.clone(), sock_addr_peer), + "sock_open" => Function::new_native_with_env(store, env.clone(), sock_open), + "sock_set_opt_flag" => Function::new_native_with_env(store, env.clone(), sock_set_opt_flag), + "sock_get_opt_flag" => Function::new_native_with_env(store, env.clone(), sock_get_opt_flag), + "sock_set_opt_time" => Function::new_native_with_env(store, env.clone(), sock_set_opt_time), + "sock_get_opt_time" => Function::new_native_with_env(store, env.clone(), sock_get_opt_time), + "sock_set_opt_size" => Function::new_native_with_env(store, env.clone(), sock_set_opt_size), + "sock_get_opt_size" => Function::new_native_with_env(store, env.clone(), sock_get_opt_size), + "sock_join_multicast_v4" => Function::new_native_with_env(store, env.clone(), sock_join_multicast_v4), + "sock_leave_multicast_v4" => Function::new_native_with_env(store, env.clone(), sock_leave_multicast_v4), + "sock_join_multicast_v6" => Function::new_native_with_env(store, env.clone(), sock_join_multicast_v6), + "sock_leave_multicast_v6" => Function::new_native_with_env(store, env.clone(), sock_leave_multicast_v6), + "sock_bind" => Function::new_native_with_env(store, env.clone(), sock_bind), + "sock_listen" => Function::new_native_with_env(store, env.clone(), sock_listen), + "sock_accept" => Function::new_native_with_env(store, env.clone(), sock_accept), + "sock_connect" => Function::new_native_with_env(store, env.clone(), sock_connect), + "sock_recv" => Function::new_native_with_env(store, env.clone(), sock_recv), + "sock_recv_from" => Function::new_native_with_env(store, env.clone(), sock_recv_from), + "sock_send" => Function::new_native_with_env(store, env.clone(), sock_send), + "sock_send_to" => Function::new_native_with_env(store, env.clone(), sock_send_to), + "sock_send_file" => Function::new_native_with_env(store, env.clone(), sock_send_file), + "sock_shutdown" => Function::new_native_with_env(store, env.clone(), sock_shutdown), + "resolve" => Function::new_native_with_env(store, env.clone(), resolve), } } } -fn generate_import_object_wasix64_v1(store: &Store, thread: WasiThread) -> Imports { +fn generate_import_object_wasix64_v1(store: &Store, env: WasiEnv) -> Imports { use self::wasix64::*; imports! { "wasix_64v1" => { - "args_get" => Function::new_native_with_env(store, thread.clone(), args_get), - "args_sizes_get" => Function::new_native_with_env(store, thread.clone(), args_sizes_get), - "clock_res_get" => Function::new_native_with_env(store, thread.clone(), clock_res_get), - "clock_time_get" => Function::new_native_with_env(store, thread.clone(), clock_time_get), - "environ_get" => Function::new_native_with_env(store, thread.clone(), environ_get), - "environ_sizes_get" => Function::new_native_with_env(store, thread.clone(), environ_sizes_get), - "fd_advise" => Function::new_native_with_env(store, thread.clone(), fd_advise), - "fd_allocate" => Function::new_native_with_env(store, thread.clone(), fd_allocate), - "fd_close" => Function::new_native_with_env(store, thread.clone(), fd_close), - "fd_datasync" => Function::new_native_with_env(store, thread.clone(), fd_datasync), - "fd_fdstat_get" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_get), - "fd_fdstat_set_flags" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_flags), - "fd_fdstat_set_rights" => Function::new_native_with_env(store, thread.clone(), fd_fdstat_set_rights), - "fd_filestat_get" => Function::new_native_with_env(store, thread.clone(), fd_filestat_get), - "fd_filestat_set_size" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_size), - "fd_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), fd_filestat_set_times), - "fd_pread" => Function::new_native_with_env(store, thread.clone(), fd_pread), - "fd_prestat_get" => Function::new_native_with_env(store, thread.clone(), fd_prestat_get), - "fd_prestat_dir_name" => Function::new_native_with_env(store, thread.clone(), fd_prestat_dir_name), - "fd_pwrite" => Function::new_native_with_env(store, thread.clone(), fd_pwrite), - "fd_read" => Function::new_native_with_env(store, thread.clone(), fd_read), - "fd_readdir" => Function::new_native_with_env(store, thread.clone(), fd_readdir), - "fd_renumber" => Function::new_native_with_env(store, thread.clone(), fd_renumber), - "fd_dup" => Function::new_native_with_env(store, thread.clone(), fd_dup), - "fd_event" => Function::new_native_with_env(store, thread.clone(), fd_event), - "fd_seek" => Function::new_native_with_env(store, thread.clone(), fd_seek), - "fd_sync" => Function::new_native_with_env(store, thread.clone(), fd_sync), - "fd_tell" => Function::new_native_with_env(store, thread.clone(), fd_tell), - "fd_write" => Function::new_native_with_env(store, thread.clone(), fd_write), - "fd_pipe" => Function::new_native_with_env(store, thread.clone(), fd_pipe), - "path_create_directory" => Function::new_native_with_env(store, thread.clone(), path_create_directory), - "path_filestat_get" => Function::new_native_with_env(store, thread.clone(), path_filestat_get), - "path_filestat_set_times" => Function::new_native_with_env(store, thread.clone(), path_filestat_set_times), - "path_link" => Function::new_native_with_env(store, thread.clone(), path_link), - "path_open" => Function::new_native_with_env(store, thread.clone(), path_open), - "path_readlink" => Function::new_native_with_env(store, thread.clone(), path_readlink), - "path_remove_directory" => Function::new_native_with_env(store, thread.clone(), path_remove_directory), - "path_rename" => Function::new_native_with_env(store, thread.clone(), path_rename), - "path_symlink" => Function::new_native_with_env(store, thread.clone(), path_symlink), - "path_unlink_file" => Function::new_native_with_env(store, thread.clone(), path_unlink_file), - "poll_oneoff" => Function::new_native_with_env(store, thread.clone(), poll_oneoff), - "proc_exit" => Function::new_native_with_env(store, thread.clone(), proc_exit), - "proc_raise" => Function::new_native_with_env(store, thread.clone(), proc_raise), - "random_get" => Function::new_native_with_env(store, thread.clone(), random_get), - "tty_get" => Function::new_native_with_env(store, thread.clone(), tty_get), - "tty_set" => Function::new_native_with_env(store, thread.clone(), tty_set), - "getcwd" => Function::new_native_with_env(store, thread.clone(), getcwd), - "chdir" => Function::new_native_with_env(store, thread.clone(), chdir), - "thread_spawn" => Function::new_native_with_env(store, thread.clone(), thread_spawn), - "thread_sleep" => Function::new_native_with_env(store, thread.clone(), thread_sleep), - "thread_id" => Function::new_native_with_env(store, thread.clone(), thread_id), - "thread_join" => Function::new_native_with_env(store, thread.clone(), thread_join), - "thread_parallelism" => Function::new_native_with_env(store, thread.clone(), thread_parallelism), - "thread_exit" => Function::new_native_with_env(store, thread.clone(), thread_exit), - "sched_yield" => Function::new_native_with_env(store, thread.clone(), sched_yield), - "getpid" => Function::new_native_with_env(store, thread.clone(), getpid), - "bus_spawn_local" => Function::new_native_with_env(store, thread.clone(), bus_spawn_local), - "bus_spawn_remote" => Function::new_native_with_env(store, thread.clone(), bus_spawn_remote), - "bus_close" => Function::new_native_with_env(store, thread.clone(), bus_close), - "bus_invoke" => Function::new_native_with_env(store, thread.clone(), bus_invoke), - "bus_fault" => Function::new_native_with_env(store, thread.clone(), bus_fault), - "bus_drop" => Function::new_native_with_env(store, thread.clone(), bus_drop), - "bus_reply" => Function::new_native_with_env(store, thread.clone(), bus_reply), - "bus_callback" => Function::new_native_with_env(store, thread.clone(), bus_callback), - "bus_listen" => Function::new_native_with_env(store, thread.clone(), bus_listen), - "bus_poll" => Function::new_native_with_env(store, thread.clone(), bus_poll), - "bus_poll_data" => Function::new_native_with_env(store, thread.clone(), bus_poll_data), - "ws_connect" => Function::new_native_with_env(store, thread.clone(), ws_connect), - "http_request" => Function::new_native_with_env(store, thread.clone(), http_request), - "http_status" => Function::new_native_with_env(store, thread.clone(), http_status), - "port_bridge" => Function::new_native_with_env(store, thread.clone(), port_bridge), - "port_unbridge" => Function::new_native_with_env(store, thread.clone(), port_unbridge), - "port_dhcp_acquire" => Function::new_native_with_env(store, thread.clone(), port_dhcp_acquire), - "port_addr_add" => Function::new_native_with_env(store, thread.clone(), port_addr_add), - "port_addr_remove" => Function::new_native_with_env(store, thread.clone(), port_addr_remove), - "port_addr_clear" => Function::new_native_with_env(store, thread.clone(), port_addr_clear), - "port_addr_list" => Function::new_native_with_env(store, thread.clone(), port_addr_list), - "port_mac" => Function::new_native_with_env(store, thread.clone(), port_mac), - "port_gateway_set" => Function::new_native_with_env(store, thread.clone(), port_gateway_set), - "port_route_add" => Function::new_native_with_env(store, thread.clone(), port_route_add), - "port_route_remove" => Function::new_native_with_env(store, thread.clone(), port_route_remove), - "port_route_clear" => Function::new_native_with_env(store, thread.clone(), port_route_clear), - "port_route_list" => Function::new_native_with_env(store, thread.clone(), port_route_list), - "sock_status" => Function::new_native_with_env(store, thread.clone(), sock_status), - "sock_addr_local" => Function::new_native_with_env(store, thread.clone(), sock_addr_local), - "sock_addr_peer" => Function::new_native_with_env(store, thread.clone(), sock_addr_peer), - "sock_open" => Function::new_native_with_env(store, thread.clone(), sock_open), - "sock_set_opt_flag" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_flag), - "sock_get_opt_flag" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_flag), - "sock_set_opt_time" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_time), - "sock_get_opt_time" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_time), - "sock_set_opt_size" => Function::new_native_with_env(store, thread.clone(), sock_set_opt_size), - "sock_get_opt_size" => Function::new_native_with_env(store, thread.clone(), sock_get_opt_size), - "sock_join_multicast_v4" => Function::new_native_with_env(store, thread.clone(), sock_join_multicast_v4), - "sock_leave_multicast_v4" => Function::new_native_with_env(store, thread.clone(), sock_leave_multicast_v4), - "sock_join_multicast_v6" => Function::new_native_with_env(store, thread.clone(), sock_join_multicast_v6), - "sock_leave_multicast_v6" => Function::new_native_with_env(store, thread.clone(), sock_leave_multicast_v6), - "sock_bind" => Function::new_native_with_env(store, thread.clone(), sock_bind), - "sock_listen" => Function::new_native_with_env(store, thread.clone(), sock_listen), - "sock_accept" => Function::new_native_with_env(store, thread.clone(), sock_accept), - "sock_connect" => Function::new_native_with_env(store, thread.clone(), sock_connect), - "sock_recv" => Function::new_native_with_env(store, thread.clone(), sock_recv), - "sock_recv_from" => Function::new_native_with_env(store, thread.clone(), sock_recv_from), - "sock_send" => Function::new_native_with_env(store, thread.clone(), sock_send), - "sock_send_to" => Function::new_native_with_env(store, thread.clone(), sock_send_to), - "sock_send_file" => Function::new_native_with_env(store, thread.clone(), sock_send_file), - "sock_shutdown" => Function::new_native_with_env(store, thread.clone(), sock_shutdown), - "resolve" => Function::new_native_with_env(store, thread.clone(), resolve), + "args_get" => Function::new_native_with_env(store, env.clone(), args_get), + "args_sizes_get" => Function::new_native_with_env(store, env.clone(), args_sizes_get), + "clock_res_get" => Function::new_native_with_env(store, env.clone(), clock_res_get), + "clock_time_get" => Function::new_native_with_env(store, env.clone(), clock_time_get), + "environ_get" => Function::new_native_with_env(store, env.clone(), environ_get), + "environ_sizes_get" => Function::new_native_with_env(store, env.clone(), environ_sizes_get), + "fd_advise" => Function::new_native_with_env(store, env.clone(), fd_advise), + "fd_allocate" => Function::new_native_with_env(store, env.clone(), fd_allocate), + "fd_close" => Function::new_native_with_env(store, env.clone(), fd_close), + "fd_datasync" => Function::new_native_with_env(store, env.clone(), fd_datasync), + "fd_fdstat_get" => Function::new_native_with_env(store, env.clone(), fd_fdstat_get), + "fd_fdstat_set_flags" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_flags), + "fd_fdstat_set_rights" => Function::new_native_with_env(store, env.clone(), fd_fdstat_set_rights), + "fd_filestat_get" => Function::new_native_with_env(store, env.clone(), fd_filestat_get), + "fd_filestat_set_size" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_size), + "fd_filestat_set_times" => Function::new_native_with_env(store, env.clone(), fd_filestat_set_times), + "fd_pread" => Function::new_native_with_env(store, env.clone(), fd_pread), + "fd_prestat_get" => Function::new_native_with_env(store, env.clone(), fd_prestat_get), + "fd_prestat_dir_name" => Function::new_native_with_env(store, env.clone(), fd_prestat_dir_name), + "fd_pwrite" => Function::new_native_with_env(store, env.clone(), fd_pwrite), + "fd_read" => Function::new_native_with_env(store, env.clone(), fd_read), + "fd_readdir" => Function::new_native_with_env(store, env.clone(), fd_readdir), + "fd_renumber" => Function::new_native_with_env(store, env.clone(), fd_renumber), + "fd_dup" => Function::new_native_with_env(store, env.clone(), fd_dup), + "fd_event" => Function::new_native_with_env(store, env.clone(), fd_event), + "fd_seek" => Function::new_native_with_env(store, env.clone(), fd_seek), + "fd_sync" => Function::new_native_with_env(store, env.clone(), fd_sync), + "fd_tell" => Function::new_native_with_env(store, env.clone(), fd_tell), + "fd_write" => Function::new_native_with_env(store, env.clone(), fd_write), + "fd_pipe" => Function::new_native_with_env(store, env.clone(), fd_pipe), + "path_create_directory" => Function::new_native_with_env(store, env.clone(), path_create_directory), + "path_filestat_get" => Function::new_native_with_env(store, env.clone(), path_filestat_get), + "path_filestat_set_times" => Function::new_native_with_env(store, env.clone(), path_filestat_set_times), + "path_link" => Function::new_native_with_env(store, env.clone(), path_link), + "path_open" => Function::new_native_with_env(store, env.clone(), path_open), + "path_readlink" => Function::new_native_with_env(store, env.clone(), path_readlink), + "path_remove_directory" => Function::new_native_with_env(store, env.clone(), path_remove_directory), + "path_rename" => Function::new_native_with_env(store, env.clone(), path_rename), + "path_symlink" => Function::new_native_with_env(store, env.clone(), path_symlink), + "path_unlink_file" => Function::new_native_with_env(store, env.clone(), path_unlink_file), + "poll_oneoff" => Function::new_native_with_env(store, env.clone(), poll_oneoff), + "proc_exit" => Function::new_native_with_env(store, env.clone(), proc_exit), + "proc_raise" => Function::new_native_with_env(store, env.clone(), proc_raise), + "random_get" => Function::new_native_with_env(store, env.clone(), random_get), + "tty_get" => Function::new_native_with_env(store, env.clone(), tty_get), + "tty_set" => Function::new_native_with_env(store, env.clone(), tty_set), + "getcwd" => Function::new_native_with_env(store, env.clone(), getcwd), + "chdir" => Function::new_native_with_env(store, env.clone(), chdir), + "thread_spawn" => Function::new_native_with_env(store, env.clone(), thread_spawn), + "thread_sleep" => Function::new_native_with_env(store, env.clone(), thread_sleep), + "thread_id" => Function::new_native_with_env(store, env.clone(), thread_id), + "thread_join" => Function::new_native_with_env(store, env.clone(), thread_join), + "thread_parallelism" => Function::new_native_with_env(store, env.clone(), thread_parallelism), + "thread_exit" => Function::new_native_with_env(store, env.clone(), thread_exit), + "sched_yield" => Function::new_native_with_env(store, env.clone(), sched_yield), + "getpid" => Function::new_native_with_env(store, env.clone(), getpid), + "process_spawn" => Function::new_native_with_env(store, env.clone(), process_spawn), + "bus_open_local" => Function::new_native_with_env(store, env.clone(), bus_open_local), + "bus_open_remote" => Function::new_native_with_env(store, env.clone(), bus_open_remote), + "bus_close" => Function::new_native_with_env(store, env.clone(), bus_close), + "bus_call" => Function::new_native_with_env(store, env.clone(), bus_call), + "bus_subcall" => Function::new_native_with_env(store, env.clone(), bus_subcall), + "bus_poll" => Function::new_native_with_env(store, env.clone(), bus_poll), + "call_reply" => Function::new_native_with_env(store, env.clone(), call_reply), + "call_fault" => Function::new_native_with_env(store, env.clone(), call_fault), + "call_close" => Function::new_native_with_env(store, env.clone(), call_close), + "ws_connect" => Function::new_native_with_env(store, env.clone(), ws_connect), + "http_request" => Function::new_native_with_env(store, env.clone(), http_request), + "http_status" => Function::new_native_with_env(store, env.clone(), http_status), + "port_bridge" => Function::new_native_with_env(store, env.clone(), port_bridge), + "port_unbridge" => Function::new_native_with_env(store, env.clone(), port_unbridge), + "port_dhcp_acquire" => Function::new_native_with_env(store, env.clone(), port_dhcp_acquire), + "port_addr_add" => Function::new_native_with_env(store, env.clone(), port_addr_add), + "port_addr_remove" => Function::new_native_with_env(store, env.clone(), port_addr_remove), + "port_addr_clear" => Function::new_native_with_env(store, env.clone(), port_addr_clear), + "port_addr_list" => Function::new_native_with_env(store, env.clone(), port_addr_list), + "port_mac" => Function::new_native_with_env(store, env.clone(), port_mac), + "port_gateway_set" => Function::new_native_with_env(store, env.clone(), port_gateway_set), + "port_route_add" => Function::new_native_with_env(store, env.clone(), port_route_add), + "port_route_remove" => Function::new_native_with_env(store, env.clone(), port_route_remove), + "port_route_clear" => Function::new_native_with_env(store, env.clone(), port_route_clear), + "port_route_list" => Function::new_native_with_env(store, env.clone(), port_route_list), + "sock_status" => Function::new_native_with_env(store, env.clone(), sock_status), + "sock_addr_local" => Function::new_native_with_env(store, env.clone(), sock_addr_local), + "sock_addr_peer" => Function::new_native_with_env(store, env.clone(), sock_addr_peer), + "sock_open" => Function::new_native_with_env(store, env.clone(), sock_open), + "sock_set_opt_flag" => Function::new_native_with_env(store, env.clone(), sock_set_opt_flag), + "sock_get_opt_flag" => Function::new_native_with_env(store, env.clone(), sock_get_opt_flag), + "sock_set_opt_time" => Function::new_native_with_env(store, env.clone(), sock_set_opt_time), + "sock_get_opt_time" => Function::new_native_with_env(store, env.clone(), sock_get_opt_time), + "sock_set_opt_size" => Function::new_native_with_env(store, env.clone(), sock_set_opt_size), + "sock_get_opt_size" => Function::new_native_with_env(store, env.clone(), sock_get_opt_size), + "sock_join_multicast_v4" => Function::new_native_with_env(store, env.clone(), sock_join_multicast_v4), + "sock_leave_multicast_v4" => Function::new_native_with_env(store, env.clone(), sock_leave_multicast_v4), + "sock_join_multicast_v6" => Function::new_native_with_env(store, env.clone(), sock_join_multicast_v6), + "sock_leave_multicast_v6" => Function::new_native_with_env(store, env.clone(), sock_leave_multicast_v6), + "sock_bind" => Function::new_native_with_env(store, env.clone(), sock_bind), + "sock_listen" => Function::new_native_with_env(store, env.clone(), sock_listen), + "sock_accept" => Function::new_native_with_env(store, env.clone(), sock_accept), + "sock_connect" => Function::new_native_with_env(store, env.clone(), sock_connect), + "sock_recv" => Function::new_native_with_env(store, env.clone(), sock_recv), + "sock_recv_from" => Function::new_native_with_env(store, env.clone(), sock_recv_from), + "sock_send" => Function::new_native_with_env(store, env.clone(), sock_send), + "sock_send_to" => Function::new_native_with_env(store, env.clone(), sock_send_to), + "sock_send_file" => Function::new_native_with_env(store, env.clone(), sock_send_file), + "sock_shutdown" => Function::new_native_with_env(store, env.clone(), sock_shutdown), + "resolve" => Function::new_native_with_env(store, env.clone(), resolve), } } } @@ -669,3 +721,12 @@ fn mem_error_to_wasi(err: MemoryAccessError) -> types::__wasi_errno_t { _ => types::__WASI_EINVAL, } } + +fn mem_error_to_bus(err: MemoryAccessError) -> types::__bus_errno_t { + match err { + MemoryAccessError::HeapOutOfBounds => types::__BUS_EMEMVIOLATION, + MemoryAccessError::Overflow => types::__BUS_EMEMVIOLATION, + MemoryAccessError::NonUtf8String => types::__BUS_EBADREQUEST, + _ => types::__BUS_EUNKNOWN, + } +} diff --git a/lib/wasi/src/macros.rs b/lib/wasi/src/macros.rs index 259fa572ca7..b9ec4245597 100644 --- a/lib/wasi/src/macros.rs +++ b/lib/wasi/src/macros.rs @@ -53,6 +53,24 @@ macro_rules! wasi_try_ok { }}; } +/// Like the `try!` macro or `?` syntax: returns the value if the computation +/// succeeded or returns the error value. +macro_rules! wasi_try_bus { + ($expr:expr) => {{ + let res: Result<_, crate::syscalls::types::__bus_errno_t> = $expr; + match res { + Ok(val) => { + tracing::trace!("wasi::wasi_try_bus::val: {:?}", val); + val + } + Err(err) => { + tracing::debug!("wasi::wasi_try_bus::err: {:?}", err); + return err; + } + } + }}; +} + /// Like `wasi_try` but converts a `MemoryAccessError` to a __wasi_errno_t`. macro_rules! wasi_try_mem { ($expr:expr) => {{ @@ -60,6 +78,13 @@ macro_rules! wasi_try_mem { }}; } +/// Like `wasi_try` but converts a `MemoryAccessError` to a __bus_errno_t`. +macro_rules! wasi_try_mem_bus { + ($expr:expr) => {{ + wasi_try_bus!($expr.map_err($crate::mem_error_to_bus)) + }}; +} + /// Like `wasi_try` but converts a `MemoryAccessError` to a __wasi_errno_t`. macro_rules! wasi_try_mem_ok { ($expr:expr) => {{ @@ -77,3 +102,9 @@ macro_rules! get_input_str { wasi_try_mem!($data.read_utf8_string($memory, $len)) }}; } + +macro_rules! get_input_str_bus { + ($memory:expr, $data:expr, $len:expr) => {{ + wasi_try_mem_bus!($data.read_utf8_string($memory, $len)) + }}; +} diff --git a/lib/wasi/src/runtime.rs b/lib/wasi/src/runtime.rs index ae196747e9d..e24f5c52f55 100644 --- a/lib/wasi/src/runtime.rs +++ b/lib/wasi/src/runtime.rs @@ -76,10 +76,8 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync { /// Spawns a new thread by invoking the fn thread_spawn( &self, - _method: &str, - _user_data: u64, - _reactor: bool, - ) -> Result { + _callback: Box, + ) -> Result<(), WasiThreadError> { Err(WasiThreadError::Unsupported) } @@ -88,11 +86,6 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync { Err(WasiThreadError::Unsupported) } - // Joins the specified thread with this thread - which effectively waits for it to exit - fn thread_join(&self, _other: WasiThreadId) -> Result<(), WasiThreadError> { - Err(WasiThreadError::Unsupported) - } - /// Invokes whenever a WASM thread goes idle. In some runtimes (like singlethreaded /// execution environments) they will need to do asynchronous work whenever the main /// thread goes idle and this is the place to hook for that. @@ -108,13 +101,13 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync { } #[derive(Debug)] -pub struct PlugableRuntimeImplementation { +pub struct PluggableRuntimeImplementation { pub bus: Box, pub networking: Box, pub thread_id_seed: AtomicU32, } -impl PlugableRuntimeImplementation { +impl PluggableRuntimeImplementation { pub fn set_bus_implementation(&mut self, bus: I) where I: VirtualBus + Sync, @@ -130,7 +123,7 @@ impl PlugableRuntimeImplementation { } } -impl Default for PlugableRuntimeImplementation { +impl Default for PluggableRuntimeImplementation { fn default() -> Self { Self { #[cfg(not(feature = "host-vnet"))] @@ -143,13 +136,15 @@ impl Default for PlugableRuntimeImplementation { } } -impl WasiRuntimeImplementation for PlugableRuntimeImplementation { +impl WasiRuntimeImplementation for PluggableRuntimeImplementation { fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { self.bus.deref() } + fn networking<'a>(&'a self) -> &'a (dyn VirtualNetworking) { self.networking.deref() } + fn thread_generate_id(&self) -> WasiThreadId { self.thread_id_seed.fetch_add(1, Ordering::Relaxed).into() } diff --git a/lib/wasi/src/state/builder.rs b/lib/wasi/src/state/builder.rs index b77d371a1c4..541b0a4a923 100644 --- a/lib/wasi/src/state/builder.rs +++ b/lib/wasi/src/state/builder.rs @@ -467,6 +467,7 @@ impl WasiStateBuilder { fs: wasi_fs, inodes: Arc::new(inodes), args: self.args.clone(), + threading: Default::default(), envs: self .envs .iter() diff --git a/lib/wasi/src/state/guard.rs b/lib/wasi/src/state/guard.rs index 17ec9164a5a..8e21647de35 100644 --- a/lib/wasi/src/state/guard.rs +++ b/lib/wasi/src/state/guard.rs @@ -1,6 +1,6 @@ use std::{sync::{ RwLockReadGuard, RwLockWriteGuard -}, io::Seek}; +}, io::{Seek, Read}}; use super::*; #[derive(Debug)] @@ -50,17 +50,19 @@ pub(crate) struct WasiStateFileGuard { impl WasiStateFileGuard { - pub fn new(state: &WasiState, fd: __wasi_fd_t) -> Result { + pub fn new(state: &WasiState, fd: __wasi_fd_t) -> Result, FsError> { let inodes = state.inodes.read().unwrap(); let fd_map = state.fs.fd_map.read().unwrap(); if let Some(fd) = fd_map.get(&fd) { let guard = inodes.arena[fd.inode].read(); if let Kind::File { .. } = guard.deref() { Ok( - Self { - inodes: state.inodes.clone(), - inode: fd.inode - } + Some( + Self { + inodes: state.inodes.clone(), + inode: fd.inode + } + ) ) } else { // Our public API should ensure that this is not possible @@ -68,7 +70,7 @@ impl WasiStateFileGuard } } else { - Err(FsError::NoDevice) + Ok(None) } } diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 5a7c08cdfaf..484bc34c780 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -28,13 +28,16 @@ pub use self::types::*; pub use self::guard::*; use crate::syscalls::types::*; use crate::utils::map_io_err; +use crate::WasiBusProcessId; +use crate::WasiThread; +use crate::WasiThreadId; use generational_arena::Arena; pub use generational_arena::Index as Inode; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; +use std::borrow::Cow; use std::collections::HashMap; use std::collections::VecDeque; -use std::io::Read; use std::sync::mpsc; use std::sync::Arc; use std::{ @@ -43,11 +46,12 @@ use std::{ ops::{Deref, DerefMut}, path::{Path, PathBuf}, sync::{ - atomic::{AtomicU32, AtomicU64, Ordering}, + atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, }, }; use tracing::{debug, trace}; +use wasmer_vbus::BusSpawnedProcess; use wasmer_vfs::{FileSystem, FsError, OpenOptions, VirtualFile}; @@ -326,6 +330,7 @@ pub struct WasiFs { pub next_fd: AtomicU32, inode_counter: AtomicU64, pub current_dir: Mutex, + pub is_wasix: AtomicBool, #[cfg_attr(feature = "enable-serde", serde(skip, default = "default_fs_backing"))] pub fs_backing: Box, } @@ -574,6 +579,7 @@ impl WasiFs { next_fd: AtomicU32::new(3), inode_counter: AtomicU64::new(1024), current_dir: Mutex::new("/".to_string()), + is_wasix: AtomicBool::new(false), fs_backing, }; wasi_fs.create_stdin(inodes); @@ -827,22 +833,25 @@ impl WasiFs { pub fn get_current_dir( &self, inodes: &mut WasiInodes, + base: __wasi_fd_t, ) -> Result<(Inode, String), __wasi_errno_t> { - self.get_current_dir_inner(inodes, 0) + self.get_current_dir_inner(inodes, base, 0) } - fn get_current_dir_inner( + pub(crate) fn get_current_dir_inner( &self, inodes: &mut WasiInodes, + base: __wasi_fd_t, symlink_count: u32, ) -> Result<(Inode, String), __wasi_errno_t> { let current_dir = { let guard = self.current_dir.lock().unwrap(); guard.clone() }; + let cur_inode = self.get_fd_inode(base)?; let inode = self.get_inode_at_path_inner( inodes, - VIRTUAL_ROOT_FD, + cur_inode, current_dir.as_str(), symlink_count, true, @@ -866,7 +875,7 @@ impl WasiFs { fn get_inode_at_path_inner( &self, inodes: &mut WasiInodes, - base: __wasi_fd_t, + mut cur_inode: generational_arena::Index, path: &str, mut symlink_count: u32, follow_symlinks: bool, @@ -876,23 +885,8 @@ impl WasiFs { } let path: &Path = Path::new(path); - let mut cur_inode = self.get_fd_inode(base)?; - if path.to_str().unwrap() == "/" && base == VIRTUAL_ROOT_FD { - return Ok(cur_inode); - } let n_components = path.components().count(); - // If this is the start of the path search and it starts with the - // current directory marker then we need to resolve the current - // path to the inode before we do the search - if path.components().next().map(|c| c.as_os_str().to_str()).flatten() == Some(".") - && base == VIRTUAL_ROOT_FD // File queries will occur on the root first - && symlink_count == 0 - // The resolving of the current path only should happen once and not after symbolic links are followed - { - (cur_inode, _) = self.get_current_dir_inner(inodes, symlink_count + 1)?; - } - // TODO: rights checks 'path_iter: for (i, component) in path.components().enumerate() { // used to terminate symlink resolution properly @@ -1090,6 +1084,8 @@ impl WasiFs { relative_path, } => { let new_base_dir = *base_po_dir; + let new_base_inode = self.get_fd_inode(new_base_dir)?; + // allocate to reborrow mutabily to recur let new_path = { /*if let Kind::Root { .. } = self.inodes[base_po_dir].kind { @@ -1106,7 +1102,7 @@ impl WasiFs { drop(guard); let symlink_inode = self.get_inode_at_path_inner( inodes, - new_base_dir, + new_base_inode, &new_path, symlink_count + 1, follow_symlinks, @@ -1236,7 +1232,15 @@ impl WasiFs { path: &str, follow_symlinks: bool, ) -> Result { - self.get_inode_at_path_inner(inodes, base, path, 0, follow_symlinks) + let start_inode; + if path.starts_with("/") == false && self.is_wasix.load(Ordering::Acquire) { + let (cur_inode, _) = self.get_current_dir(inodes, base)?; + start_inode = cur_inode; + } else { + start_inode = self.get_fd_inode(base)?; + } + + self.get_inode_at_path_inner(inodes, start_inode, path, 0, follow_symlinks) } /// Returns the parent Dir or Root that the file at a given path is in and the file name @@ -1362,19 +1366,23 @@ impl WasiFs { let inode_val = &inodes.arena[inode]; if inode_val.is_preopened { - Ok(__wasi_prestat_t { - pr_type: __WASI_PREOPENTYPE_DIR, - u: PrestatEnum::Dir { - // REVIEW: - pr_name_len: inode_val.name.len() as u32 + 1, - } - .untagged(), - }) + Ok(self.prestat_fd_inner(inode_val)) } else { Err(__WASI_EBADF) } } + pub(crate) fn prestat_fd_inner(&self, inode_val: &InodeVal) -> __wasi_prestat_t { + __wasi_prestat_t { + pr_type: __WASI_PREOPENTYPE_DIR, + u: PrestatEnum::Dir { + // REVIEW: + pr_name_len: inode_val.name.len() as u32 + 1, + } + .untagged(), + } + } + pub fn flush(&self, inodes: &WasiInodes, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> { match fd { __WASI_STDIN_FILENO => (), @@ -1791,6 +1799,20 @@ impl WasiState { } } +/// Structures used for the threading and sub-processes +/// +/// These internal implementation details are hidden away from the +/// consumer who should instead implement the vbus trait on the runtime +#[derive(Debug, Default)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub(crate) struct WasiStateThreading { + pub threads: HashMap, + pub thread_seed: u32, + pub processes: HashMap, + pub process_reuse: HashMap, WasiBusProcessId>, + pub process_seed: u32, +} + /// Top level data type containing all* the state with which WASI can /// interact. /// @@ -1824,6 +1846,7 @@ impl WasiState { pub struct WasiState { pub fs: WasiFs, pub inodes: Arc>, + pub(crate) threading: Mutex, pub args: Vec>, pub envs: Vec>, } @@ -1851,32 +1874,68 @@ impl WasiState { /// Get the `VirtualFile` object at stdout pub fn stdout( &self, - ) -> Result, FsError> { + ) -> Result>, FsError> { self.std_dev_get(__WASI_STDOUT_FILENO) } + #[deprecated( + since = "3.0.0", + note = "stdout_mut() is no longer needed - just use stdout() instead" + )] + pub fn stdout_mut( + &self + ) -> Result>, FsError> { + self.stdout() + } + /// Get the `VirtualFile` object at stderr pub fn stderr( &self, - ) -> Result, FsError> { + ) -> Result>, FsError> { self.std_dev_get(__WASI_STDERR_FILENO) } + #[deprecated( + since = "3.0.0", + note = "stderr_mut() is no longer needed - just use stderr() instead" + )] + pub fn stderr_mut( + &self + ) -> Result>, FsError> { + self.stderr() + } + /// Get the `VirtualFile` object at stdin pub fn stdin( &self, - ) -> Result, FsError> { + ) -> Result>, FsError> { self.std_dev_get(__WASI_STDIN_FILENO) } + #[deprecated( + since = "3.0.0", + note = "stdin_mut() is no longer needed - just use stdin() instead" + )] + pub fn stdin_mut( + &self + ) -> Result>, FsError> { + self.stdin() + } + /// Internal helper function to get a standard device handle. /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. fn std_dev_get( &self, fd: __wasi_fd_t, - ) -> Result, FsError> { + ) -> Result>, FsError> { + let ret = WasiStateFileGuard::new(self, fd)? + .map(|a| { + let ret = Box::new(a); + let ret: Box = ret; + ret + }); Ok( - Box::new(WasiStateFileGuard::new(self, fd)?) + ret ) } } diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 58d270c5c95..86954e9aeb1 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -10,6 +10,7 @@ use std::{ sync::{Arc, Mutex}, time::Duration, }; +use wasmer_vbus::BusError; #[cfg(feature = "host-fs")] pub use wasmer_vfs::host_fs::{Stderr, Stdin, Stdout}; @@ -101,6 +102,56 @@ pub fn net_error_into_wasi_err(net_error: NetworkError) -> __wasi_errno_t { } } +pub fn bus_error_into_wasi_err(bus_error: BusError) -> __bus_errno_t { + use BusError::*; + match bus_error { + Serialization => __BUS_ESER, + Deserialization => __BUS_EDES, + InvalidWapm => __BUS_EWAPM, + FetchFailed => __BUS_EFETCH, + CompileError => __BUS_ECOMPILE, + InvalidABI => __BUS_EABI, + Aborted => __BUS_EABORTED, + BadHandle => __BUS_EBADHANDLE, + InvalidTopic => __BUS_ETOPIC, + BadCallback => __BUS_EBADCB, + Unsupported => __BUS_EUNSUPPORTED, + BadRequest => __BUS_EBADREQUEST, + AccessDenied => __BUS_EDENIED, + InternalError => __BUS_EINTERNAL, + MemoryAllocationFailed => __BUS_EALLOC, + InvokeFailed => __BUS_EINVOKE, + AlreadyConsumed => __BUS_ECONSUMED, + MemoryAccessViolation => __BUS_EMEMVIOLATION, + UnknownError => __BUS_EUNKNOWN, + } +} + +pub fn wasi_error_into_bus_err(bus_error: __bus_errno_t) -> BusError { + use BusError::*; + match bus_error { + __BUS_ESER => Serialization, + __BUS_EDES => Deserialization, + __BUS_EWAPM => InvalidWapm, + __BUS_EFETCH => FetchFailed, + __BUS_ECOMPILE => CompileError, + __BUS_EABI => InvalidABI, + __BUS_EABORTED => Aborted, + __BUS_EBADHANDLE => BadHandle, + __BUS_ETOPIC => InvalidTopic, + __BUS_EBADCB => BadCallback, + __BUS_EUNSUPPORTED => Unsupported, + __BUS_EBADREQUEST => BadRequest, + __BUS_EDENIED => AccessDenied, + __BUS_EINTERNAL => InternalError, + __BUS_EALLOC => MemoryAllocationFailed, + __BUS_EINVOKE => InvokeFailed, + __BUS_ECONSUMED => AlreadyConsumed, + __BUS_EMEMVIOLATION => MemoryAccessViolation, + __BUS_EUNKNOWN | _ => UnknownError, + } +} + #[derive(Debug, Clone)] #[allow(clippy::enum_variant_names)] pub enum PollEvent { diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index 374c180a1ad..615e0bee4d2 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -10,11 +10,11 @@ use wasmer::WasmPtr; /// Wasm memory. If the memory clobbered by the current syscall is also used by /// that syscall, then it may break. pub fn fd_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: types::__wasi_fd_t, buf: WasmPtr, ) -> types::__wasi_errno_t { - let memory = thread.memory(); + let memory = env.memory(); // transmute the WasmPtr into a WasmPtr where T2 > T1, this will read extra memory. // The edge case of this cenv.mausing an OOB is not handled, if the new field is OOB, then the entire @@ -26,10 +26,10 @@ pub fn fd_filestat_get( // Set up complete, make the call with the pointer that will write to the // struct and some unrelated memory after the struct. - let result = syscalls::fd_filestat_get::(thread, fd, new_buf); + let result = syscalls::fd_filestat_get::(env, fd, new_buf); // reborrow memory - let memory = thread.memory(); + let memory = env.memory(); // get the values written to memory let new_filestat = wasi_try_mem!(new_buf.deref(memory).read()); @@ -59,7 +59,7 @@ pub fn fd_filestat_get( /// Wrapper around `syscalls::path_filestat_get` with extra logic to handle the size /// difference of `wasi_filestat_t` pub fn path_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: types::__wasi_fd_t, flags: types::__wasi_lookupflags_t, path: WasmPtr, @@ -67,15 +67,14 @@ pub fn path_filestat_get( buf: WasmPtr, ) -> types::__wasi_errno_t { // see `fd_filestat_get` in this file for an explanation of this strange behavior - let memory = thread.memory(); + let memory = env.memory(); let new_buf: WasmPtr = buf.cast(); let new_filestat_setup: types::__wasi_filestat_t = wasi_try_mem!(new_buf.read(memory)); - let result = - syscalls::path_filestat_get::(thread, fd, flags, path, path_len, new_buf); + let result = syscalls::path_filestat_get::(env, fd, flags, path, path_len, new_buf); - let memory = thread.memory(); + let memory = env.memory(); let new_filestat = wasi_try_mem!(new_buf.deref(memory).read()); let old_stat = snapshot0::__wasi_filestat_t { st_dev: new_filestat.st_dev, @@ -97,7 +96,7 @@ pub fn path_filestat_get( /// Wrapper around `syscalls::fd_seek` with extra logic to remap the values /// of `__wasi_whence_t` pub fn fd_seek( - thread: &WasiThread, + env: &WasiEnv, fd: types::__wasi_fd_t, offset: types::__wasi_filedelta_t, whence: snapshot0::__wasi_whence_t, @@ -110,13 +109,13 @@ pub fn fd_seek( // if it's invalid, let the new fd_seek handle it _ => whence, }; - syscalls::fd_seek::(thread, fd, offset, new_whence, newoffset) + syscalls::fd_seek::(env, fd, offset, new_whence, newoffset) } /// Wrapper around `syscalls::poll_oneoff` with extra logic to add the removed /// userdata field back pub fn poll_oneoff( - thread: &WasiThread, + env: &WasiEnv, in_: WasmPtr, out_: WasmPtr, nsubscriptions: u32, @@ -126,7 +125,7 @@ pub fn poll_oneoff( // we just need to readjust and copy it // we start by adjusting `in_` into a format that the new code can understand - let memory = thread.memory(); + let memory = env.memory(); let nsubscriptions_offset: u32 = nsubscriptions.into(); let in_origs = wasi_try_mem_ok!(in_.slice(memory, nsubscriptions_offset)); let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); @@ -160,10 +159,10 @@ pub fn poll_oneoff( // make the call let result = - syscalls::poll_oneoff::(thread, in_new_type_ptr, out_, nsubscriptions, nevents); + syscalls::poll_oneoff::(env, in_new_type_ptr, out_, nsubscriptions, nevents); // replace the old values of in, in case the calling code reuses the memory - let memory = thread.memory(); + let memory = env.memory(); for (in_sub, orig) in wasi_try_mem_ok!(in_.slice(memory, nsubscriptions_offset)) .iter() diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index f220aa0e7e4..d66bcc15368 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -22,8 +22,9 @@ pub mod wasix32; pub mod wasix64; use self::types::*; -use crate::state::InodeHttpSocketType; +use crate::state::{bus_error_into_wasi_err, wasi_error_into_bus_err, InodeHttpSocketType}; use crate::utils::map_io_err; +use crate::WasiBusProcessId; use crate::{ mem_error_to_wasi, state::{ @@ -34,7 +35,7 @@ use crate::{ WasiEnv, WasiError, WasiThread, WasiThreadId, }; use bytes::Bytes; -use std::borrow::Borrow; +use std::borrow::{Borrow, Cow}; use std::convert::{Infallible, TryInto}; use std::io::{self, Read, Seek, Write}; use std::mem::transmute; @@ -44,8 +45,9 @@ use std::sync::atomic::AtomicU64; use std::sync::{atomic::Ordering, Mutex}; use std::sync::{mpsc, Arc}; use std::time::Duration; -use tracing::{debug, error, trace}; +use tracing::{debug, error, trace, warn}; use wasmer::{Memory, Memory32, Memory64, MemorySize, RuntimeError, Value, WasmPtr, WasmSlice}; +use wasmer_vbus::{FileDescriptor, StdioMode}; use wasmer_vfs::{FsError, VirtualFile}; use wasmer_vnet::{SocketHttpRequest, StreamSecurity}; @@ -133,7 +135,7 @@ fn has_rights(rights_set: __wasi_rights_t, rights_check_set: __wasi_rights_t) -> } fn __sock_actor( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, rights: __wasi_rights_t, actor: F, @@ -141,7 +143,7 @@ fn __sock_actor( where F: FnOnce(&crate::state::InodeSocket) -> Result, { - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = state.fs.get_fd(sock)?; let ret = { @@ -167,7 +169,7 @@ where } fn __sock_actor_mut( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, rights: __wasi_rights_t, actor: F, @@ -175,7 +177,7 @@ fn __sock_actor_mut( where F: FnOnce(&mut crate::state::InodeSocket) -> Result, { - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = state.fs.get_fd(sock)?; let ret = { @@ -201,7 +203,7 @@ where } fn __sock_upgrade( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, rights: __wasi_rights_t, actor: F, @@ -211,7 +213,7 @@ where &mut crate::state::InodeSocket, ) -> Result, __wasi_errno_t>, { - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = state.fs.get_fd(sock)?; if rights != 0 { @@ -289,12 +291,12 @@ fn get_current_time_in_nanos() -> Result<__wasi_timestamp_t, __wasi_errno_t> { /// A pointer to a buffer to write the argument string data. /// pub fn args_get( - thread: &WasiThread, + env: &WasiEnv, argv: WasmPtr, M>, argv_buf: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::args_get"); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (memory, state) = env.get_memory_and_wasi_state(0); let result = write_buffer_array(memory, &*state.args, argv, argv_buf); @@ -320,12 +322,12 @@ pub fn args_get( /// - `size_t *argv_buf_size` /// The size of the argument string data. pub fn args_sizes_get( - thread: &WasiThread, + env: &WasiEnv, argc: WasmPtr, argv_buf_size: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::args_sizes_get"); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (memory, state) = env.get_memory_and_wasi_state(0); let argc = argc.deref(memory); let argv_buf_size = argv_buf_size.deref(memory); @@ -351,12 +353,12 @@ pub fn args_sizes_get( /// - `__wasi_timestamp_t *resolution` /// The resolution of the clock in nanoseconds pub fn clock_res_get( - thread: &WasiThread, + env: &WasiEnv, clock_id: __wasi_clockid_t, resolution: WasmPtr<__wasi_timestamp_t, M>, ) -> __wasi_errno_t { trace!("wasi::clock_res_get"); - let memory = thread.memory(); + let memory = env.memory(); let out_addr = resolution.deref(memory); let t_out = wasi_try!(platform_clock_res_get(clock_id, out_addr)); @@ -375,7 +377,7 @@ pub fn clock_res_get( /// - `__wasi_timestamp_t *time` /// The value of the clock in nanoseconds pub fn clock_time_get( - thread: &WasiThread, + env: &WasiEnv, clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, time: WasmPtr<__wasi_timestamp_t, M>, @@ -384,7 +386,7 @@ pub fn clock_time_get( "wasi::clock_time_get clock_id: {}, precision: {}", clock_id, precision ); - let memory = thread.memory(); + let memory = env.memory(); let t_out = wasi_try!(platform_clock_time_get(clock_id, precision)); wasi_try_mem!(time.write(memory, t_out as __wasi_timestamp_t)); @@ -407,7 +409,7 @@ pub fn clock_time_get( /// - `char *environ_buf` /// A pointer to a buffer to write the environment variable string data. pub fn environ_get( - thread: &WasiThread, + env: &WasiEnv, environ: WasmPtr, M>, environ_buf: WasmPtr, ) -> __wasi_errno_t { @@ -415,7 +417,7 @@ pub fn environ_get( "wasi::environ_get. Environ: {:?}, environ_buf: {:?}", environ, environ_buf ); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (memory, state) = env.get_memory_and_wasi_state(0); trace!(" -> State envs: {:?}", state.envs); write_buffer_array(memory, &*state.envs, environ, environ_buf) @@ -429,12 +431,12 @@ pub fn environ_get( /// - `size_t *environ_buf_size` /// The size of the environment variable string data. pub fn environ_sizes_get( - thread: &WasiThread, + env: &WasiEnv, environ_count: WasmPtr, environ_buf_size: WasmPtr, ) -> __wasi_errno_t { trace!("wasi::environ_sizes_get"); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (memory, state) = env.get_memory_and_wasi_state(0); let environ_count = environ_count.deref(memory); let environ_buf_size = environ_buf_size.deref(memory); @@ -467,7 +469,7 @@ pub fn environ_sizes_get( /// - `__wasi_advice_t advice` /// The advice to give pub fn fd_advise( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, @@ -490,13 +492,13 @@ pub fn fd_advise( /// - `__wasi_filesize_t len` /// The length from the offset marking the end of the allocation pub fn fd_allocate( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, ) -> __wasi_errno_t { debug!("wasi::fd_allocate"); - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; @@ -540,9 +542,9 @@ pub fn fd_allocate( /// If `fd` is a directory /// - `__WASI_EBADF` /// If `fd` is invalid or not open -pub fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { +pub fn fd_close(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_close: fd={}", fd); - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); @@ -556,9 +558,9 @@ pub fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { /// Inputs: /// - `__wasi_fd_t fd` /// The file descriptor to sync -pub fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { +pub fn fd_datasync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_datasync"); - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_DATASYNC) { return __WASI_EACCES; @@ -580,7 +582,7 @@ pub fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { /// - `__wasi_fdstat_t *buf` /// The location where the metadata will be written pub fn fd_fdstat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf_ptr: WasmPtr<__wasi_fdstat_t, M>, ) -> __wasi_errno_t { @@ -589,7 +591,7 @@ pub fn fd_fdstat_get( fd, buf_ptr.offset() ); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let stat = wasi_try!(state.fs.fdstat(inodes.deref(), fd)); wasi_try_mem!(buf_ptr.write(memory, stat)); @@ -605,12 +607,12 @@ pub fn fd_fdstat_get( /// - `__wasi_fdflags_t flags` /// The flags to apply to `fd` pub fn fd_fdstat_set_flags( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_fdflags_t, ) -> __wasi_errno_t { debug!("wasi::fd_fdstat_set_flags"); - let (_, state) = thread.get_memory_and_wasi_state(0); + let (_, state) = env.get_memory_and_wasi_state(0); let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -632,13 +634,13 @@ pub fn fd_fdstat_set_flags( /// - `__wasi_rights_t fs_rights_inheriting` /// The inheriting rights to apply to `fd` pub fn fd_fdstat_set_rights( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, fs_rights_base: __wasi_rights_t, fs_rights_inheriting: __wasi_rights_t, ) -> __wasi_errno_t { debug!("wasi::fd_fdstat_set_rights"); - let (_, state) = thread.get_memory_and_wasi_state(0); + let (_, state) = env.get_memory_and_wasi_state(0); let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -664,12 +666,12 @@ pub fn fd_fdstat_set_rights( /// - `__wasi_filestat_t *buf` /// Where the metadata from `fd` will be written pub fn fd_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr<__wasi_filestat_t, M>, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_get"); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_FILESTAT_GET) { return __WASI_EACCES; @@ -690,12 +692,12 @@ pub fn fd_filestat_get( /// - `__wasi_filesize_t st_size` /// New size that `fd` will be set to pub fn fd_filestat_set_size( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, st_size: __wasi_filesize_t, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_set_size"); - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; @@ -738,14 +740,14 @@ pub fn fd_filestat_set_size( /// - `__wasi_fstflags_t fst_flags` /// Bit-vector for controlling which times get set pub fn fd_filestat_set_times( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, st_atim: __wasi_timestamp_t, st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { debug!("wasi::fd_filestat_set_times"); - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_FILESTAT_SET_TIMES) { @@ -799,7 +801,7 @@ pub fn fd_filestat_set_times( /// - `size_t nread` /// The number of bytes read pub fn fd_pread( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t, M>, iovs_len: M::Offset, @@ -807,7 +809,7 @@ pub fn fd_pread( nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_pread: fd={}, offset={}", fd, offset); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let iovs = wasi_try_mem_ok!(iovs.slice(memory, iovs_len)); let nread_ref = nread.deref(memory); @@ -819,10 +821,10 @@ pub fn fd_pread( inodes .stdin_mut(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ); if let Some(ref mut stdin) = guard.deref_mut() { - wasi_try_ok!(read_bytes(stdin, memory, iovs), thread) + wasi_try_ok!(read_bytes(stdin, memory, iovs), env) } else { return Ok(__WASI_EBADF); } @@ -848,27 +850,24 @@ pub fn fd_pread( wasi_try_ok!( h.seek(std::io::SeekFrom::Start(offset as u64)) .map_err(map_io_err), - thread + env ); - wasi_try_ok!(read_bytes(h, memory, iovs), thread) + wasi_try_ok!(read_bytes(h, memory, iovs), env) } else { return Ok(__WASI_EINVAL); } } Kind::Socket { socket } => { - wasi_try_ok!(socket.recv(memory, iovs), thread) + wasi_try_ok!(socket.recv(memory, iovs), env) } Kind::Pipe { pipe } => { - wasi_try_ok!(pipe.recv(memory, iovs), thread) + wasi_try_ok!(pipe.recv(memory, iovs), env) } Kind::EventNotifications { .. } => return Ok(__WASI_EINVAL), Kind::Dir { .. } | Kind::Root { .. } => return Ok(__WASI_EISDIR), Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_pread"), Kind::Buffer { buffer } => { - wasi_try_ok!( - read_bytes(&buffer[(offset as usize)..], memory, iovs), - thread - ) + wasi_try_ok!(read_bytes(&buffer[(offset as usize)..], memory, iovs), env) } } } @@ -889,12 +888,12 @@ pub fn fd_pread( /// - `__wasi_prestat *buf` /// Where the metadata will be written pub fn fd_prestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr<__wasi_prestat_t, M>, ) -> __wasi_errno_t { trace!("wasi::fd_prestat_get: fd={}", fd); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); wasi_try_mem!(buf.write(memory, wasi_try!(state.fs.prestat_fd(inodes.deref(), fd)))); @@ -902,7 +901,7 @@ pub fn fd_prestat_get( } pub fn fd_prestat_dir_name( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: M::Offset, @@ -912,7 +911,7 @@ pub fn fd_prestat_dir_name( fd, path_len ); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let path_chars = wasi_try_mem!(path.slice(memory, path_len)); let real_inode = wasi_try!(state.fs.get_fd_inode(fd)); @@ -963,7 +962,7 @@ pub fn fd_prestat_dir_name( /// - `u32 *nwritten` /// Number of bytes written pub fn fd_pwrite( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t, M>, iovs_len: M::Offset, @@ -972,7 +971,7 @@ pub fn fd_pwrite( ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_pwrite"); // TODO: refactor, this is just copied from `fd_write`... - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let iovs_arr = wasi_try_mem_ok!(iovs.slice(memory, iovs_len)); let nwritten_ref = nwritten.deref(memory); @@ -984,10 +983,10 @@ pub fn fd_pwrite( inodes .stdout_mut(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ); if let Some(ref mut stdout) = guard.deref_mut() { - wasi_try_ok!(write_bytes(stdout, memory, iovs_arr), thread) + wasi_try_ok!(write_bytes(stdout, memory, iovs_arr), env) } else { return Ok(__WASI_EBADF); } @@ -997,10 +996,10 @@ pub fn fd_pwrite( inodes .stderr_mut(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ); if let Some(ref mut stderr) = guard.deref_mut() { - wasi_try_ok!(write_bytes(stderr, memory, iovs_arr), thread) + wasi_try_ok!(write_bytes(stderr, memory, iovs_arr), env) } else { return Ok(__WASI_EBADF); } @@ -1023,18 +1022,18 @@ pub fn fd_pwrite( handle .seek(std::io::SeekFrom::Start(offset as u64)) .map_err(map_io_err), - thread + env ); - wasi_try_ok!(write_bytes(handle, memory, iovs_arr), thread) + wasi_try_ok!(write_bytes(handle, memory, iovs_arr), env) } else { return Ok(__WASI_EINVAL); } } Kind::Socket { socket } => { - wasi_try_ok!(socket.send(memory, iovs_arr), thread) + wasi_try_ok!(socket.send(memory, iovs_arr), env) } Kind::Pipe { pipe } => { - wasi_try_ok!(pipe.send(memory, iovs_arr), thread) + wasi_try_ok!(pipe.send(memory, iovs_arr), env) } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify @@ -1045,7 +1044,7 @@ pub fn fd_pwrite( Kind::Buffer { buffer } => { wasi_try_ok!( write_bytes(&mut buffer[(offset as usize)..], memory, iovs_arr), - thread + env ) } } @@ -1073,14 +1072,14 @@ pub fn fd_pwrite( /// Number of bytes read /// pub fn fd_read( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t, M>, iovs_len: M::Offset, nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_read: fd={}", fd); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let iovs_arr = wasi_try_mem_ok!(iovs.slice(memory, iovs_len)); let nread_ref = nread.deref(memory); @@ -1092,10 +1091,10 @@ pub fn fd_read( inodes .stdin_mut(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ); if let Some(ref mut stdin) = guard.deref_mut() { - wasi_try_ok!(read_bytes(stdin, memory, iovs_arr), thread) + wasi_try_ok!(read_bytes(stdin, memory, iovs_arr), env) } else { return Ok(__WASI_EBADF); } @@ -1121,18 +1120,18 @@ pub fn fd_read( handle .seek(std::io::SeekFrom::Start(offset as u64)) .map_err(map_io_err), - thread + env ); - wasi_try_ok!(read_bytes(handle, memory, iovs_arr), thread) + wasi_try_ok!(read_bytes(handle, memory, iovs_arr), env) } else { return Ok(__WASI_EINVAL); } } Kind::Socket { socket } => { - wasi_try_ok!(socket.recv(memory, iovs_arr), thread) + wasi_try_ok!(socket.recv(memory, iovs_arr), env) } Kind::Pipe { pipe } => { - wasi_try_ok!(pipe.recv(memory, iovs_arr), thread) + wasi_try_ok!(pipe.recv(memory, iovs_arr), env) } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify @@ -1172,7 +1171,7 @@ pub fn fd_read( let reader = val.to_ne_bytes(); ret = wasi_try_ok!( read_bytes(&reader[..], memory, iovs_arr), - thread + env ); break; } else { @@ -1186,16 +1185,16 @@ pub fn fd_read( } // Yield for a fixed period of time and then check again - thread.yield_now()?; + env.yield_now()?; if rx.recv_timeout(Duration::from_millis(5)).is_err() { - thread.sleep(Duration::from_millis(5))?; + env.sleep(Duration::from_millis(5))?; } } ret } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_read"), Kind::Buffer { buffer } => { - wasi_try_ok!(read_bytes(&buffer[offset..], memory, iovs_arr), thread) + wasi_try_ok!(read_bytes(&buffer[offset..], memory, iovs_arr), env) } } }; @@ -1231,7 +1230,7 @@ pub fn fd_read( /// The Number of bytes stored in `buf`; if less than `buf_len` then entire /// directory has been read pub fn fd_readdir( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr, buf_len: M::Offset, @@ -1239,7 +1238,7 @@ pub fn fd_readdir( bufused: WasmPtr, ) -> __wasi_errno_t { trace!("wasi::fd_readdir"); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); // TODO: figure out how this is supposed to work; // is it supposed to pack the buffer full every time until it can't? or do one at a time? @@ -1358,9 +1357,9 @@ pub fn fd_readdir( /// File descriptor to copy /// - `__wasi_fd_t to` /// Location to copy file descriptor to -pub fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { +pub fn fd_renumber(env: &WasiEnv, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_renumber: from={}, to={}", from, to); - let (_, state) = thread.get_memory_and_wasi_state(0); + let (_, state) = env.get_memory_and_wasi_state(0); let mut fd_map = state.fs.fd_map.write().unwrap(); let fd_entry = wasi_try!(fd_map.get_mut(&from).ok_or(__WASI_EBADF)); @@ -1385,13 +1384,13 @@ pub fn fd_renumber(thread: &WasiThread, from: __wasi_fd_t, to: __wasi_fd_t) -> _ /// - `__wasi_fd_t fd` /// The new file handle that is a duplicate of the original pub fn fd_dup( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, ret_fd: WasmPtr<__wasi_fd_t, M>, ) -> __wasi_errno_t { debug!("wasi::fd_dup"); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (memory, state) = env.get_memory_and_wasi_state(0); let fd = wasi_try!(state.fs.clone_fd(fd)); wasi_try_mem!(ret_fd.write(memory, fd)); @@ -1402,14 +1401,14 @@ pub fn fd_dup( /// ### `fd_event()` /// Creates a file handle for event notifications pub fn fd_event( - thread: &WasiThread, + env: &WasiEnv, initial_val: u64, flags: __wasi_eventfdflags, ret_fd: WasmPtr<__wasi_fd_t, M>, ) -> __wasi_errno_t { debug!("wasi::fd_event"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let kind = Kind::EventNotifications { counter: Arc::new(AtomicU64::new(initial_val)), @@ -1444,14 +1443,14 @@ pub fn fd_event( /// - `__wasi_filesize_t *fd` /// The new offset relative to the start of the file pub fn fd_seek( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filedelta_t, whence: __wasi_whence_t, newoffset: WasmPtr<__wasi_filesize_t, M>, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_seek: fd={}, offset={}", fd, offset); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let new_offset_ref = newoffset.deref(memory); let fd_entry = wasi_try_ok!(state.fs.get_fd(fd)); @@ -1474,7 +1473,7 @@ pub fn fd_seek( Kind::File { ref mut handle, .. } => { if let Some(handle) = handle { let end = - wasi_try_ok!(handle.seek(SeekFrom::End(0)).map_err(map_io_err), thread); + wasi_try_ok!(handle.seek(SeekFrom::End(0)).map_err(map_io_err), env); // TODO: handle case if fd_entry.offset uses 64 bits of a u64 drop(guard); @@ -1526,10 +1525,10 @@ pub fn fd_seek( /// TODO: figure out which errors this should return /// - `__WASI_EPERM` /// - `__WASI_ENOTCAPABLE` -pub fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { +pub fn fd_sync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_sync"); debug!("=> fd={}", fd); - let (_, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_SYNC) { return __WASI_EACCES; @@ -1568,12 +1567,12 @@ pub fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { /// - `__wasi_filesize_t *offset` /// The offset of `fd` relative to the start of the file pub fn fd_tell( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: WasmPtr<__wasi_filesize_t, M>, ) -> __wasi_errno_t { debug!("wasi::fd_tell"); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (memory, state) = env.get_memory_and_wasi_state(0); let offset_ref = offset.deref(memory); let fd_entry = wasi_try!(state.fs.get_fd(fd)); @@ -1602,14 +1601,14 @@ pub fn fd_tell( /// Errors: /// pub fn fd_write( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t, M>, iovs_len: M::Offset, nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::fd_write: fd={}", fd); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let iovs_arr = wasi_try_mem_ok!(iovs.slice(memory, iovs_len)); let nwritten_ref = nwritten.deref(memory); @@ -1621,10 +1620,10 @@ pub fn fd_write( inodes .stdout_mut(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ); if let Some(ref mut stdout) = guard.deref_mut() { - wasi_try_ok!(write_bytes(stdout, memory, iovs_arr), thread) + wasi_try_ok!(write_bytes(stdout, memory, iovs_arr), env) } else { return Ok(__WASI_EBADF); } @@ -1634,10 +1633,10 @@ pub fn fd_write( inodes .stderr_mut(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ); if let Some(ref mut stderr) = guard.deref_mut() { - wasi_try_ok!(write_bytes(stderr, memory, iovs_arr), thread) + wasi_try_ok!(write_bytes(stderr, memory, iovs_arr), env) } else { return Ok(__WASI_EBADF); } @@ -1660,18 +1659,18 @@ pub fn fd_write( handle .seek(std::io::SeekFrom::Start(offset as u64)) .map_err(map_io_err), - thread + env ); - wasi_try_ok!(write_bytes(handle, memory, iovs_arr), thread) + wasi_try_ok!(write_bytes(handle, memory, iovs_arr), env) } else { return Ok(__WASI_EINVAL); } } Kind::Socket { socket } => { - wasi_try_ok!(socket.send(memory, iovs_arr), thread) + wasi_try_ok!(socket.send(memory, iovs_arr), env) } Kind::Pipe { pipe } => { - wasi_try_ok!(pipe.send(memory, iovs_arr), thread) + wasi_try_ok!(pipe.send(memory, iovs_arr), env) } Kind::Dir { .. } | Kind::Root { .. } => { // TODO: verify @@ -1701,7 +1700,7 @@ pub fn fd_write( } Kind::Symlink { .. } => unimplemented!("Symlinks in wasi::fd_write"), Kind::Buffer { buffer } => { - wasi_try_ok!(write_bytes(&mut buffer[offset..], memory, iovs_arr), thread) + wasi_try_ok!(write_bytes(&mut buffer[offset..], memory, iovs_arr), env) } } }; @@ -1712,7 +1711,7 @@ pub fn fd_write( let fd_entry = wasi_try_ok!(fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); fd_entry.offset += bytes_written as u64; } - wasi_try_ok!(state.fs.filestat_resync_size(inodes.deref(), fd), thread); + wasi_try_ok!(state.fs.filestat_resync_size(inodes.deref(), fd), env); bytes_written } @@ -1733,13 +1732,13 @@ pub fn fd_write( /// - `__wasi_fd_t` /// Second file handle that represents the other end of the pipe pub fn fd_pipe( - thread: &WasiThread, + env: &WasiEnv, ro_fd1: WasmPtr<__wasi_fd_t, M>, ro_fd2: WasmPtr<__wasi_fd_t, M>, ) -> __wasi_errno_t { trace!("wasi::fd_pipe"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let (pipe1, pipe2) = WasiPipe::new(); @@ -1780,13 +1779,13 @@ pub fn fd_pipe( /// - __WASI_RIGHT_PATH_CREATE_DIRECTORY /// This right must be set on the directory that the file is created in (TODO: verify that this is true) pub fn path_create_directory( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: M::Offset, ) -> __wasi_errno_t { debug!("wasi::path_create_directory"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let working_dir = wasi_try!(state.fs.get_fd(fd)); { @@ -1907,15 +1906,15 @@ pub fn path_create_directory( /// - `__wasi_file_stat_t *buf` /// The location where the metadata will be stored pub fn path_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, path_len: M::Offset, buf: WasmPtr<__wasi_filestat_t, M>, ) -> __wasi_errno_t { - debug!("wasi::path_filestat_get"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + debug!("wasi::path_filestat_get (fd={})", fd); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let path_string = unsafe { get_input_str!(memory, path, path_len) }; @@ -1999,7 +1998,7 @@ pub fn path_filestat_get_internal( /// - `__wasi_fstflags_t fst_flags` /// A bitmask controlling which attributes are set pub fn path_filestat_set_times( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, @@ -2009,7 +2008,7 @@ pub fn path_filestat_set_times( fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { debug!("wasi::path_filestat_set_times"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let fd_entry = wasi_try!(state.fs.get_fd(fd)); let fd_inode = fd_entry.inode; if !has_rights(fd_entry.rights, __WASI_RIGHT_PATH_FILESTAT_SET_TIMES) { @@ -2076,7 +2075,7 @@ pub fn path_filestat_set_times( /// - `u32 old_path_len` /// Length of the `new_path` string pub fn path_link( - thread: &WasiThread, + env: &WasiEnv, old_fd: __wasi_fd_t, old_flags: __wasi_lookupflags_t, old_path: WasmPtr, @@ -2089,7 +2088,7 @@ pub fn path_link( if old_flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 { debug!(" - will follow symlinks when opening path"); } - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let old_path_str = unsafe { get_input_str!(memory, old_path, old_path_len) }; let new_path_str = unsafe { get_input_str!(memory, new_path, new_path_len) }; let source_fd = wasi_try!(state.fs.get_fd(old_fd)); @@ -2171,7 +2170,7 @@ pub fn path_link( /// Possible Errors: /// - `__WASI_EACCES`, `__WASI_EBADF`, `__WASI_EFAULT`, `__WASI_EFBIG?`, `__WASI_EINVAL`, `__WASI_EIO`, `__WASI_ELOOP`, `__WASI_EMFILE`, `__WASI_ENAMETOOLONG?`, `__WASI_ENFILE`, `__WASI_ENOENT`, `__WASI_ENOTDIR`, `__WASI_EROFS`, and `__WASI_ENOTCAPABLE` pub fn path_open( - thread: &WasiThread, + env: &WasiEnv, dirfd: __wasi_fd_t, dirflags: __wasi_lookupflags_t, path: WasmPtr, @@ -2186,7 +2185,7 @@ pub fn path_open( if dirflags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0 { debug!(" - will follow symlinks when opening path"); } - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); /* TODO: find actual upper bound on name size (also this is a path, not a name :think-fish:) */ let path_len64: u64 = path_len.into(); if path_len64 > 1024u64 * 1024u64 { @@ -2413,7 +2412,7 @@ pub fn path_open( /// - `u32 buf_used` /// The number of bytes written to `buf` pub fn path_readlink( - thread: &WasiThread, + env: &WasiEnv, dir_fd: __wasi_fd_t, path: WasmPtr, path_len: M::Offset, @@ -2422,7 +2421,7 @@ pub fn path_readlink( buf_used: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::path_readlink"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let base_dir = wasi_try!(state.fs.get_fd(dir_fd)); if !has_rights(base_dir.rights, __WASI_RIGHT_PATH_READLINK) { @@ -2462,14 +2461,14 @@ pub fn path_readlink( /// Returns __WASI_ENOTEMTPY if directory is not empty pub fn path_remove_directory( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: M::Offset, ) -> __wasi_errno_t { // TODO check if fd is a dir, ensure it's within sandbox, etc. debug!("wasi::path_remove_directory"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let base_dir = wasi_try!(state.fs.get_fd(fd)); let path_str = unsafe { get_input_str!(memory, path, path_len) }; @@ -2546,7 +2545,7 @@ pub fn path_remove_directory( /// - `u32 new_path_len` /// The number of bytes to read from `new_path` pub fn path_rename( - thread: &WasiThread, + env: &WasiEnv, old_fd: __wasi_fd_t, old_path: WasmPtr, old_path_len: M::Offset, @@ -2558,7 +2557,7 @@ pub fn path_rename( "wasi::path_rename: old_fd = {}, new_fd = {}", old_fd, new_fd ); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let source_str = unsafe { get_input_str!(memory, old_path, old_path_len) }; let source_path = std::path::Path::new(&source_str); let target_str = unsafe { get_input_str!(memory, new_path, new_path_len) }; @@ -2709,7 +2708,7 @@ pub fn path_rename( /// - `u32 new_path_len` /// The number of bytes to read from `new_path` pub fn path_symlink( - thread: &WasiThread, + env: &WasiEnv, old_path: WasmPtr, old_path_len: M::Offset, fd: __wasi_fd_t, @@ -2717,7 +2716,7 @@ pub fn path_symlink( new_path_len: M::Offset, ) -> __wasi_errno_t { debug!("wasi::path_symlink"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let old_path_str = unsafe { get_input_str!(memory, old_path, old_path_len) }; let new_path_str = unsafe { get_input_str!(memory, new_path, new_path_len) }; let base_fd = wasi_try!(state.fs.get_fd(fd)); @@ -2808,13 +2807,13 @@ pub fn path_symlink( /// - `u32 path_len` /// The number of bytes in the `path` array pub fn path_unlink_file( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: M::Offset, ) -> __wasi_errno_t { debug!("wasi::path_unlink_file"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let base_dir = wasi_try!(state.fs.get_fd(fd)); if !has_rights(base_dir.rights, __WASI_RIGHT_PATH_UNLINK_FILE) { @@ -2918,7 +2917,7 @@ pub fn path_unlink_file( /// - `u32 nevents` /// The number of events seen pub fn poll_oneoff( - thread: &WasiThread, + env: &WasiEnv, in_: WasmPtr<__wasi_subscription_t, M>, out_: WasmPtr<__wasi_event_t, M>, nsubscriptions: M::Offset, @@ -2926,7 +2925,7 @@ pub fn poll_oneoff( ) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::poll_oneoff"); trace!(" => nsubscriptions = {}", nsubscriptions); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let subscription_array = wasi_try_mem_ok!(in_.slice(memory, nsubscriptions)); let event_array = wasi_try_mem_ok!(out_.slice(memory, nsubscriptions)); @@ -2947,7 +2946,7 @@ pub fn poll_oneoff( match fd { __WASI_STDIN_FILENO | __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => (), _ => { - let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), thread); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), env); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_READ) { return Ok(__WASI_EACCES); } @@ -2960,7 +2959,7 @@ pub fn poll_oneoff( match fd { __WASI_STDIN_FILENO | __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => (), _ => { - let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), thread); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), env); if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_WRITE) { return Ok(__WASI_EACCES); } @@ -2991,7 +2990,7 @@ pub fn poll_oneoff( inodes .stderr(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ) } __WASI_STDIN_FILENO => { @@ -2999,7 +2998,7 @@ pub fn poll_oneoff( inodes .stdin(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ) } __WASI_STDOUT_FILENO => { @@ -3007,11 +3006,11 @@ pub fn poll_oneoff( inodes .stdout(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ) } _ => { - let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), thread); + let fd_entry = wasi_try_ok!(state.fs.get_fd(fd), env); let inode = fd_entry.inode; if !has_rights(fd_entry.rights, __WASI_RIGHT_POLL_FD_READWRITE) { return Ok(__WASI_EACCES); @@ -3071,13 +3070,13 @@ pub fn poll_oneoff( Duration::from_millis(1), ) { Ok(0) => { - thread.yield_now()?; + env.yield_now()?; } Ok(a) => { triggered = a; } Err(FsError::WouldBlock) => { - thread.sleep(Duration::from_millis(1))?; + env.sleep(Duration::from_millis(1))?; } Err(err) => { return Ok(fs_error_into_wasi_err(err)); @@ -3103,7 +3102,7 @@ pub fn poll_oneoff( fds[i] .bytes_available_read() .map_err(fs_error_into_wasi_err), - thread + env ) .unwrap_or(0usize); error = __WASI_ESUCCESS; @@ -3113,7 +3112,7 @@ pub fn poll_oneoff( fds[i] .bytes_available_write() .map_err(fs_error_into_wasi_err), - thread + env ) .unwrap_or(0usize); error = __WASI_ESUCCESS; @@ -3167,7 +3166,7 @@ pub fn poll_oneoff( /// Inputs: /// - `__wasi_exitcode_t` /// Exit code to return to the operating system -pub fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { +pub fn proc_exit(env: &WasiEnv, code: __wasi_exitcode_t) -> Result<(), WasiError> { debug!("wasi::proc_exit, {}", code); Err(WasiError::Exit(code)) } @@ -3178,16 +3177,16 @@ pub fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), Was /// Inputs: /// - `__wasi_signal_t` /// Signal to be raised for this process -pub fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { +pub fn proc_raise(env: &WasiEnv, sig: __wasi_signal_t) -> __wasi_errno_t { debug!("wasi::proc_raise"); unimplemented!("wasi::proc_raise") } /// ### `sched_yield()` /// Yields execution of the thread -pub fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { +pub fn sched_yield(env: &WasiEnv) -> Result<__wasi_errno_t, WasiError> { trace!("wasi::sched_yield"); - thread.yield_now()?; + env.yield_now()?; Ok(__WASI_ESUCCESS) } @@ -3199,12 +3198,12 @@ pub fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { /// - `size_t buf_len` /// The number of bytes that will be written pub fn random_get( - thread: &WasiThread, + env: &WasiEnv, buf: WasmPtr, buf_len: M::Offset, ) -> __wasi_errno_t { trace!("wasi::random_get buf_len: {}", buf_len); - let memory = thread.memory(); + let memory = env.memory(); let buf_len64: u64 = buf_len.into(); let mut u8_buffer = vec![0; buf_len64 as usize]; let res = getrandom::getrandom(&mut u8_buffer); @@ -3221,12 +3220,12 @@ pub fn random_get( /// ### `tty_get()` /// Retrieves the current state of the TTY pub fn tty_get( - thread: &WasiThread, + env: &WasiEnv, tty_state: WasmPtr<__wasi_tty_t, M>, ) -> __wasi_errno_t { debug!("wasi::tty_stdin"); - let state = thread.env.runtime.tty_get(); + let state = env.runtime.tty_get(); let state = __wasi_tty_t { cols: state.cols, rows: state.rows, @@ -3254,7 +3253,7 @@ pub fn tty_get( }, }; - let memory = thread.memory(); + let memory = env.memory(); wasi_try_mem!(tty_state.write(memory, state)); __WASI_ESUCCESS @@ -3263,12 +3262,12 @@ pub fn tty_get( /// ### `tty_set()` /// Updates the properties of the rect pub fn tty_set( - thread: &WasiThread, + env: &WasiEnv, tty_state: WasmPtr<__wasi_tty_t, M>, ) -> __wasi_errno_t { debug!("wasi::tty_stdout"); - let memory = thread.memory(); + let memory = env.memory(); let state = wasi_try_mem!(tty_state.read(memory)); let state = super::runtime::WasiTtyState { cols: state.cols, @@ -3302,7 +3301,7 @@ pub fn tty_set( }, }; - thread.env.runtime.tty_set(state); + env.runtime.tty_set(state); __WASI_ESUCCESS } @@ -3312,39 +3311,53 @@ pub fn tty_set( /// If the path exceeds the size of the buffer then this function /// will fill the path_len with the needed size and return EOVERFLOW pub fn getcwd( - thread: &WasiThread, + env: &WasiEnv, path: WasmPtr, path_len: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::getpwd"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); - let (_, cur_dir) = wasi_try!(state.fs.get_current_dir(inodes.deref_mut())); - let cur_dir = cur_dir.as_bytes(); + let (_, cur_dir) = wasi_try!(state + .fs + .get_current_dir(inodes.deref_mut(), crate::VIRTUAL_ROOT_FD,)); let max_path_len = wasi_try_mem!(path_len.read(memory)); let path_slice = wasi_try_mem!(path.slice(memory, max_path_len)); + let max_path_len: u64 = max_path_len.into(); + let cur_dir = cur_dir.as_bytes(); wasi_try_mem!(path_len.write(memory, wasi_try!(to_offset::(cur_dir.len())))); - let max_path_len: u64 = max_path_len.into(); - if cur_dir.len() as u64 > max_path_len { + if cur_dir.len() as u64 >= max_path_len { return __WASI_EOVERFLOW; } - wasi_try_mem!(path_slice.write_slice(cur_dir)); + let cur_dir = { + let mut u8_buffer = vec![0; max_path_len as usize]; + let cur_dir_len = cur_dir.len(); + if (cur_dir_len as u64) < max_path_len { + u8_buffer[..cur_dir_len].clone_from_slice(cur_dir); + u8_buffer[cur_dir_len] = 0; + } else { + return __WASI_EOVERFLOW; + } + u8_buffer + }; + + wasi_try_mem!(path_slice.write_slice(&cur_dir[..])); __WASI_ESUCCESS } /// ### `chdir()` /// Sets the current working directory pub fn chdir( - thread: &WasiThread, + env: &WasiEnv, path: WasmPtr, path_len: M::Offset, ) -> __wasi_errno_t { debug!("wasi::chdir"); - let (memory, state) = thread.get_memory_and_wasi_state(0); + let (memory, state) = env.get_memory_and_wasi_state(0); let path = unsafe { get_input_str!(memory, path, path_len) }; state.fs.set_current_dir(path.as_str()); @@ -3370,7 +3383,7 @@ pub fn chdir( /// Returns the thread index of the newly created thread /// (indices always start from zero) pub fn thread_spawn( - thread: &WasiThread, + env: &WasiEnv, method: WasmPtr, method_len: M::Offset, user_data: u64, @@ -3378,21 +3391,67 @@ pub fn thread_spawn( ret_tid: WasmPtr<__wasi_tid_t, M>, ) -> __wasi_errno_t { debug!("wasi::thread_spawn"); - let memory = thread.memory(); + let memory = env.memory(); let method = unsafe { get_input_str!(memory, method, method_len) }; + + // Load the callback function + if method.as_str() != "_thread_start" { + return __WASI_ENOTCAPABLE; + }; + let funct = unsafe { + if env.thread_start_ref().is_none() { + return __WASI_EADDRNOTAVAIL; + } + env.thread_start_ref_unchecked() + }; + let reactor = match reactor { __WASI_BOOL_FALSE => false, __WASI_BOOL_TRUE => true, _ => return __WASI_EINVAL, }; - let child = wasi_try!(thread - .env - .runtime - .thread_spawn(method.as_str(), user_data, reactor) - .map_err(|err| { - let err: __wasi_errno_t = err.into(); - err - })); + + // Create the sub-thread + let mut sub_env = env.clone(); + let mut sub_thread = env.new_thread(); + sub_env.id = sub_thread.id; + + let child = { + let id = sub_thread.id; + wasi_try!(env + .runtime + .thread_spawn(Box::new(move || { + if let Some(funct) = sub_env.thread_start_ref() { + if let Err(err) = funct.call(user_data) { + warn!("thread failed: {}", err); + std::mem::forget(sub_thread); + return; + } + } else { + warn!("failed to start thread: missing callback '__wasix_thread_start'"); + std::mem::forget(sub_thread); + return; + } + + let thread = { + let mut guard = sub_env.state.threading.lock().unwrap(); + let thread = guard.threads.remove(&id); + drop(guard); + thread + }; + + if let Some(thread) = thread { + let mut thread_guard = thread.exit.lock().unwrap(); + thread_guard.take(); + } + drop(sub_thread); + })) + .map_err(|err| { + let err: __wasi_errno_t = err.into(); + err + })); + id + }; let child: __wasi_tid_t = child.into(); wasi_try_mem!(ret_tid.write(memory, child)); @@ -3406,13 +3465,13 @@ pub fn thread_spawn( /// /// * `duration` - Amount of time that the thread should sleep pub fn thread_sleep( - thread: &WasiThread, + env: &WasiEnv, duration: __wasi_timestamp_t, ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::thread_sleep"); let duration = Duration::from_nanos(duration as u64); - thread.sleep(duration)?; + env.sleep(duration)?; Ok(__WASI_ESUCCESS) } @@ -3420,13 +3479,13 @@ pub fn thread_sleep( /// Returns the index of the current thread /// (threads indices are sequencial from zero) pub fn thread_id( - thread: &WasiThread, + env: &WasiEnv, ret_tid: WasmPtr<__wasi_tid_t, M>, ) -> __wasi_errno_t { debug!("wasi::thread_id"); - let tid: __wasi_tid_t = thread.id.into(); - wasi_try_mem!(ret_tid.write(thread.memory(), tid)); + let tid: __wasi_tid_t = env.id.into(); + wasi_try_mem!(ret_tid.write(env.memory(), tid)); __WASI_ESUCCESS } @@ -3437,47 +3496,53 @@ pub fn thread_id( /// ## Parameters /// /// * `tid` - Handle of the thread to wait on -pub fn thread_join(thread: &WasiThread, tid: __wasi_tid_t) -> __wasi_errno_t { +pub fn thread_join(env: &WasiEnv, tid: __wasi_tid_t) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::thread_join"); let tid: WasiThreadId = tid.into(); - wasi_try!(thread.env.runtime().thread_join(tid).map_err(|err| { - let err: __wasi_errno_t = err.into(); - err - })); - - __WASI_ESUCCESS + let other_thread = { + let guard = env.state.threading.lock().unwrap(); + guard.threads.get(&tid).map(|a| a.clone()) + }; + if let Some(other_thread) = other_thread { + loop { + if other_thread.join(Duration::from_millis(5)) == true { + break; + } + env.yield_now()?; + } + Ok(__WASI_ESUCCESS) + } else { + Ok(__WASI_ESUCCESS) + } } /// ### `thread_parallelism()` /// Returns the available parallelism which is normally the /// number of available cores that can run concurrently pub fn thread_parallelism( - thread: &WasiThread, + env: &WasiEnv, ret_parallelism: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::thread_parallelism"); - let parallelism = wasi_try!(thread.runtime().thread_parallelism().map_err(|err| { + let parallelism = wasi_try!(env.runtime().thread_parallelism().map_err(|err| { let err: __wasi_errno_t = err.into(); err })); let parallelism: M::Offset = wasi_try!(parallelism.try_into().map_err(|_| __WASI_EOVERFLOW)); - wasi_try_mem!(ret_parallelism.write(thread.memory(), parallelism)); + wasi_try_mem!(ret_parallelism.write(env.memory(), parallelism)); __WASI_ESUCCESS } /// ### `getpid()` /// Returns the handle of the current process -pub fn getpid( - thread: &WasiThread, - ret_pid: WasmPtr<__wasi_pid_t, M>, -) -> __wasi_errno_t { +pub fn getpid(env: &WasiEnv, ret_pid: WasmPtr<__wasi_pid_t, M>) -> __wasi_errno_t { debug!("wasi::getpid"); - let pid = thread.runtime().getpid(); + let pid = env.runtime().getpid(); if let Some(pid) = pid { - wasi_try_mem!(ret_pid.write(thread.memory(), pid as __wasi_pid_t)); + wasi_try_mem!(ret_pid.write(env.memory(), pid as __wasi_pid_t)); __WASI_ESUCCESS } else { __WASI_ENOTSUP @@ -3494,16 +3559,14 @@ pub fn getpid( /// /// * `rval` - The exit code returned by the process. pub fn thread_exit( - thread: &WasiThread, + env: &WasiEnv, exitcode: __wasi_exitcode_t, ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::thread_exit"); Err(WasiError::Exit(exitcode)) } -/// ### `bus_spawn_local()` -/// Spawns a new bus process for a particular web WebAssembly -/// binary that is referenced by its process name. +/// Spawns a new process within the context of this machine /// /// ## Parameters /// @@ -3522,8 +3585,8 @@ pub fn thread_exit( /// ## Return /// /// Returns a bus process id that can be used to invoke calls -pub fn bus_spawn_local( - thread: &WasiThread, +pub fn process_spawn( + env: &WasiEnv, name: WasmPtr, name_len: M::Offset, chroot: __wasi_bool_t, @@ -3537,86 +3600,232 @@ pub fn bus_spawn_local( working_dir: WasmPtr, working_dir_len: M::Offset, ret_handles: WasmPtr<__wasi_bus_handles_t, M>, -) -> __wasi_errno_t { - debug!("wasi::bus_spawn_local"); - unimplemented!("wasi::bus_spawn_local") +) -> __bus_errno_t { + let bus = env.runtime.bus(); + let memory = env.memory(); + let name = unsafe { get_input_str_bus!(memory, name, name_len) }; + let args = unsafe { get_input_str_bus!(memory, args, args_len) }; + let preopen = unsafe { get_input_str_bus!(memory, preopen, preopen_len) }; + let working_dir = unsafe { get_input_str_bus!(memory, working_dir, working_dir_len) }; + let chroot = chroot == __WASI_BOOL_TRUE; + debug!("wasi::process_spawn (name={})", name); + + let args: Vec<_> = args.split(&['\n', '\r']).map(|a| a.to_string()).collect(); + + let preopen: Vec<_> = preopen + .split(&['\n', '\r']) + .map(|a| a.to_string()) + .collect(); + + let conv_stdio_mode = |mode: __wasi_stdiomode_t| match mode { + __WASI_STDIO_MODE_PIPED => StdioMode::Piped, + __WASI_STDIO_MODE_INHERIT => StdioMode::Inherit, + __WASI_STDIO_MODE_LOG => StdioMode::Log, + __WASI_STDIO_MODE_NULL | _ => StdioMode::Null, + }; + + let process = wasi_try_bus!(bus + .new_spawn() + .chroot(chroot) + .args(args) + .preopen(preopen) + .stdin_mode(conv_stdio_mode(stdin)) + .stdout_mode(conv_stdio_mode(stdout)) + .stderr_mode(conv_stdio_mode(stderr)) + .working_dir(working_dir) + .spawn(name.as_str()) + .map_err(bus_error_into_wasi_err)); + + let conv_stdio_fd = |a: Option| match a { + Some(fd) => __wasi_option_fd_t { + tag: __WASI_OPTION_SOME, + fd: fd.into(), + }, + None => __wasi_option_fd_t { + tag: __WASI_OPTION_NONE, + fd: 0, + }, + }; + + // Convert the stdio + let stdin = conv_stdio_fd(process.inst.stdin_fd()); + let stdout = conv_stdio_fd(process.inst.stdout_fd()); + let stderr = conv_stdio_fd(process.inst.stderr_fd()); + + // Add the process to the environment state + let bid = { + let mut guard = env.state.threading.lock().unwrap(); + guard.process_seed += 1; + let bid = guard.process_seed; + guard.processes.insert(bid.into(), process); + bid + }; + + let handles = __wasi_bus_handles_t { + bid: bid, + stdin, + stdout, + stderr, + }; + + wasi_try_mem_bus!(ret_handles.write(memory, handles)); + + __BUS_ESUCCESS } -/// ### `bus_spawn_remote()` /// Spawns a new bus process for a particular web WebAssembly -/// binary that is referenced by its process name on a remote instance +/// binary that is referenced by its process name. /// /// ## Parameters /// /// * `name` - Name of the process to be spawned -/// * `chroot` - Indicates if the process will chroot or not -/// * `args` - List of the arguments to pass the process -/// (entries are separated by line feeds) -/// * `preopen` - List of the preopens for this process -/// (entries are separated by line feeds) -/// * `working_dir` - Working directory where this process should run -/// (passing '.' will use the current directory) -/// * `stdin` - How will stdin be handled -/// * `stdout` - How will stdout be handled -/// * `stderr` - How will stderr be handled +/// * `reuse` - Indicates if the existing processes should be reused +/// if they are already running +/// +/// ## Return +/// +/// Returns a bus process id that can be used to invoke calls +pub fn bus_open_local( + env: &WasiEnv, + name: WasmPtr, + name_len: M::Offset, + reuse: __wasi_bool_t, + ret_bid: WasmPtr<__wasi_bid_t, M>, +) -> __bus_errno_t { + let bus = env.runtime.bus(); + let memory = env.memory(); + let name = unsafe { get_input_str_bus!(memory, name, name_len) }; + let reuse = reuse == __WASI_BOOL_TRUE; + debug!("wasi::bus_open_local (name={}, reuse={})", name, reuse); + + bus_open_local_internal(env, name, reuse, None, None, ret_bid) +} + +/// Spawns a new bus process for a particular web WebAssembly +/// binary that is referenced by its process name on a remote instance. +/// +/// ## Parameters +/// +/// * `name` - Name of the process to be spawned +/// * `reuse` - Indicates if the existing processes should be reused +/// if they are already running /// * `instance` - Instance identifier where this process will be spawned /// * `token` - Acceess token used to authenticate with the instance /// /// ## Return /// /// Returns a bus process id that can be used to invoke calls -pub fn bus_spawn_remote( - thread: &WasiThread, +pub fn bus_open_remote( + env: &WasiEnv, name: WasmPtr, name_len: M::Offset, - chroot: __wasi_bool_t, - args: WasmPtr, - args_len: M::Offset, - preopen: WasmPtr, - preopen_len: M::Offset, - working_dir: WasmPtr, - working_dir_len: M::Offset, - stdin: __wasi_stdiomode_t, - stdout: __wasi_stdiomode_t, - stderr: __wasi_stdiomode_t, + reuse: __wasi_bool_t, instance: WasmPtr, instance_len: M::Offset, token: WasmPtr, token_len: M::Offset, - ret_handles: WasmPtr<__wasi_bus_handles_t, M>, -) -> __wasi_errno_t { - debug!("wasi::bus_spawn_remote"); - unimplemented!("wasi::bus_spawn_remote") + ret_bid: WasmPtr<__wasi_bid_t, M>, +) -> __bus_errno_t { + let bus = env.runtime.bus(); + let memory = env.memory(); + let name = unsafe { get_input_str_bus!(memory, name, name_len) }; + let instance = unsafe { get_input_str_bus!(memory, instance, instance_len) }; + let token = unsafe { get_input_str_bus!(memory, token, token_len) }; + let reuse = reuse == __WASI_BOOL_TRUE; + debug!( + "wasi::bus_open_remote (name={}, reuse={}, instance={})", + name, reuse, instance + ); + + bus_open_local_internal(env, name, reuse, Some(instance), Some(token), ret_bid) +} + +fn bus_open_local_internal( + env: &WasiEnv, + name: String, + reuse: bool, + instance: Option, + token: Option, + ret_bid: WasmPtr<__wasi_bid_t, M>, +) -> __bus_errno_t { + let bus = env.runtime.bus(); + let memory = env.memory(); + let name: Cow<'static, str> = name.into(); + + // Check if it already exists + if reuse { + let guard = env.state.threading.lock().unwrap(); + if let Some(bid) = guard.process_reuse.get(&name) { + if guard.processes.contains_key(bid) { + wasi_try_mem_bus!(ret_bid.write(memory, bid.clone().into())); + return __BUS_ESUCCESS; + } + } + } + + let mut process = bus.new_spawn(); + process + .reuse(reuse) + .stdin_mode(StdioMode::Null) + .stdout_mode(StdioMode::Null) + .stderr_mode(StdioMode::Log); + + if let Some(instance) = instance { + process.remote_instance(instance); + } + + if let Some(token) = token { + process.access_token(token); + } + + let process = wasi_try_bus!(process + .spawn(name.as_ref()) + .map_err(bus_error_into_wasi_err)); + + // Add the process to the environment state + let bid = { + let mut guard = env.state.threading.lock().unwrap(); + guard.process_seed += 1; + let bid: WasiBusProcessId = guard.process_seed.into(); + guard.processes.insert(bid, process); + guard.process_reuse.insert(name, bid); + bid + }; + + wasi_try_mem_bus!(ret_bid.write(memory, bid.into())); + + __BUS_ESUCCESS } -/// ### `bus_close()` /// Closes a bus process and releases all associated resources /// /// ## Parameters /// /// * `bid` - Handle of the bus process handle to be closed -pub fn bus_close(thread: &WasiThread, bid: __wasi_bid_t) -> __wasi_errno_t { - debug!("wasi::bus_close"); - unimplemented!("wasi::bus_close") +pub fn bus_close(env: &WasiEnv, bid: __wasi_bid_t) -> __bus_errno_t { + trace!("wasi::bus_close (bid={})", bid); + let bid: WasiBusProcessId = bid.into(); + + let mut guard = env.state.threading.lock().unwrap(); + guard.processes.remove(&bid); + + __BUS_EUNSUPPORTED } -/// ### `bus_invoke()` /// Invokes a call within a running bus process. /// /// ## Parameters /// /// * `bid` - Handle of the bus process to invoke the call within -/// * `parent` - Optional parent bus call that this is related to /// * `keep_alive` - Causes the call handle to remain open even when A /// reply is received. It is then the callers responsibility /// to invoke 'bus_drop' when they are finished with the call /// * `topic` - Topic that describes the type of call to made /// * `format` - Format of the data pushed onto the bus /// * `buf` - The buffer where data to be transmitted is stored -pub fn bus_invoke( - thread: &WasiThread, +pub fn bus_call( + env: &WasiEnv, bid: __wasi_bid_t, - cid: WasmPtr<__wasi_option_cid_t, M>, keep_alive: __wasi_bool_t, topic: WasmPtr, topic_len: M::Offset, @@ -3624,153 +3833,141 @@ pub fn bus_invoke( buf: WasmPtr, buf_len: M::Offset, ret_cid: WasmPtr<__wasi_cid_t, M>, -) -> __wasi_errno_t { - debug!("wasi::bus_invoke"); - unimplemented!("wasi::bus_invoke") -} - -/// ### `bus_fault()` -/// Causes a fault on a particular call that was made -/// to this process from another process; where 'bid' -/// is the callering process context. -/// -/// ## Parameters -/// -/// * `cid` - Handle of the call to raise a fault on -/// * `fault` - Fault to be raised on the bus -pub fn bus_fault(thread: &WasiThread, cid: __wasi_cid_t, fault: __bus_errno_t) -> __wasi_errno_t { - debug!("wasi::bus_fault"); - unimplemented!("wasi::bus_fault") -} - -/// ### `bus_drop()` -/// Closes a bus call based on its bus call handle -/// -/// ## Parameters -/// -/// * `cid` - Handle of the bus call handle to be dropped -pub fn bus_drop(thread: &WasiThread, cid: __wasi_cid_t) -> __wasi_errno_t { - debug!("wasi::bus_drop"); - unimplemented!("wasi::bus_drop") -} +) -> __bus_errno_t { + let bus = env.runtime.bus(); + let memory = env.memory(); + let topic = unsafe { get_input_str_bus!(memory, topic, topic_len) }; + let keep_alive = keep_alive == __WASI_BOOL_TRUE; + trace!( + "wasi::bus_call (bid={}, topic={}, buf_len={})", + bid, + topic, + buf_len + ); -/// ### `bus_reply()` -/// Replies to a call that was made to this process -/// from another process; where 'cid' is the call context. -/// This will may also drop the handle and release any -/// associated resources (if keepalive is not set) -/// -/// ## Parameters -/// -/// * `cid` - Handle of the call to send a reply on -/// * `format` - Format of the data pushed onto the bus -/// * `buf` - The buffer where data to be transmitted is stored -pub fn bus_reply( - thread: &WasiThread, - cid: __wasi_cid_t, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: M::Offset, -) -> __wasi_errno_t { - debug!("wasi::bus_reply"); - unimplemented!("wasi::bus_reply") + __BUS_EUNSUPPORTED } -/// ### `bus_callback()` -/// Invokes a callback within the calling process against -/// a particular bus call represented by 'cid'. +/// Invokes a call within the context of another call /// /// ## Parameters /// -/// * `cid` - Handle of the call where a callback will be send -/// * `topic` - Topic that describes the type of callback +/// * `parent` - Parent bus call that this is related to +/// * `keep_alive` - Causes the call handle to remain open even when A +/// reply is received. It is then the callers responsibility +/// to invoke 'bus_drop' when they are finished with the call +/// * `topic` - Topic that describes the type of call to made /// * `format` - Format of the data pushed onto the bus /// * `buf` - The buffer where data to be transmitted is stored -pub fn bus_callback( - thread: &WasiThread, - cid: __wasi_cid_t, +pub fn bus_subcall( + env: &WasiEnv, + parent: __wasi_cid_t, + keep_alive: __wasi_bool_t, topic: WasmPtr, topic_len: M::Offset, format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: M::Offset, -) -> __wasi_errno_t { - debug!("wasi::bus_callback"); - unimplemented!("wasi::bus_callback") -} + ret_cid: WasmPtr<__wasi_cid_t, M>, +) -> __bus_errno_t { + let bus = env.runtime.bus(); + let memory = env.memory(); + let topic = unsafe { get_input_str_bus!(memory, topic, topic_len) }; + let keep_alive = keep_alive == __WASI_BOOL_TRUE; + trace!( + "wasi::bus_subcall (parent={}, topic={}, buf_len={})", + parent, + topic, + buf_len + ); -/// ### `bus_listen()` -/// Tells the operating system that this process is -/// now listening for bus calls on a particular topic -/// -/// ## Parameters -/// -/// * `parent` - Optional parent bus call that this is related to -/// * `topic` - Topic that describes the process will listen forcalls on -pub fn bus_listen( - thread: &WasiThread, - parent: WasmPtr<__wasi_option_cid_t, M>, - topic: WasmPtr, - topic_len: M::Offset, -) -> __wasi_errno_t { - debug!("wasi::bus_listen"); - unimplemented!("wasi::bus_listen") + __BUS_EUNSUPPORTED } -/// ### `bus_poll()` /// Polls for any outstanding events from a particular /// bus process by its handle /// /// ## Parameters /// -/// * `bid` - Handle of the bus process to poll for new events -/// (if no process is supplied then it polls for the current process) /// * `timeout` - Timeout before the poll returns, if one passed 0 /// as the timeout then this call is non blocking. /// * `events` - An events buffer that will hold any received bus events +/// * `malloc` - Name of the function that will be invoked to allocate memory +/// Function signature fn(u64) -> u64 /// /// ## Return /// /// Returns the number of events that have occured pub fn bus_poll( - thread: &WasiThread, - bid: WasmPtr<__wasi_option_bid_t, M>, - timeout: WasmPtr<__wasi_timestamp_t, M>, + env: &WasiEnv, + timeout: __wasi_timestamp_t, events: WasmPtr, nevents: M::Offset, + malloc: WasmPtr, + malloc_len: M::Offset, ret_nevents: WasmPtr, -) -> __wasi_errno_t { - debug!("wasi::bus_poll"); - unimplemented!("wasi::bus_poll") +) -> __bus_errno_t { + let bus = env.runtime.bus(); + let memory = env.memory(); + let malloc = unsafe { get_input_str_bus!(memory, malloc, malloc_len) }; + trace!("wasi::bus_poll (timeout={}, malloc={})", timeout, malloc); + + __BUS_EUNSUPPORTED } -/// ### `bus_poll_data()` -/// Receives the next event data from the bus +/// Replies to a call that was made to this process +/// from another process; where 'cid' is the call context. +/// This will may also drop the handle and release any +/// associated resources (if keepalive is not set) /// /// ## Parameters /// -/// * `bid` - Handle of the bus process to poll for new events -/// (if no process is supplied then it polls for the current process) -/// * `timeout` - Timeout before the poll returns, if one passed 0 -/// as the timeout then this call is non blocking. -/// * `topic` - The topic that describes the event that happened -/// * `buf` - The buffer where event data is stored -/// -/// ## Return -/// -/// Returns the number of events that have occured -pub fn bus_poll_data( - thread: &WasiThread, - bid: WasmPtr<__wasi_option_bid_t, M>, - timeout: WasmPtr<__wasi_timestamp_t, M>, - topic: WasmPtr, - topic_len: M::Offset, +/// * `cid` - Handle of the call to send a reply on +/// * `format` - Format of the data pushed onto the bus +/// * `buf` - The buffer where data to be transmitted is stored +pub fn call_reply( + env: &WasiEnv, + cid: __wasi_cid_t, + format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: M::Offset, - ret_evt: WasmPtr<__wasi_busevent_data_t, M>, -) -> __wasi_errno_t { - debug!("wasi::bus_poll_data"); - unimplemented!("wasi::bus_poll_data") +) -> __bus_errno_t { + let bus = env.runtime.bus(); + trace!( + "wasi::call_reply (cid={}, format={}, data_len={})", + cid, + format, + buf_len + ); + + __BUS_EUNSUPPORTED +} + +/// Causes a fault on a particular call that was made +/// to this process from another process; where 'bid' +/// is the callering process context. +/// +/// ## Parameters +/// +/// * `cid` - Handle of the call to raise a fault on +/// * `fault` - Fault to be raised on the bus +pub fn call_fault(env: &WasiEnv, cid: __wasi_cid_t, fault: __bus_errno_t) -> __bus_errno_t { + let bus = env.runtime.bus(); + debug!("wasi::call_fault (cid={}, fault={})", cid, fault); + + __BUS_EUNSUPPORTED +} + +/// Closes a bus call based on its bus call handle +/// +/// ## Parameters +/// +/// * `cid` - Handle of the bus call handle to be dropped +pub fn call_close(env: &WasiEnv, cid: __wasi_cid_t) -> __bus_errno_t { + let bus = env.runtime.bus(); + trace!("wasi::call_close (cid={})", cid); + + __BUS_EUNSUPPORTED } /// ### `ws_connect()` @@ -3784,21 +3981,21 @@ pub fn bus_poll_data( /// /// Returns a socket handle which is used to send and receive data pub fn ws_connect( - thread: &WasiThread, + env: &WasiEnv, url: WasmPtr, url_len: M::Offset, ret_sock: WasmPtr<__wasi_fd_t, M>, ) -> __wasi_errno_t { debug!("wasi::ws_connect"); - let memory = thread.memory(); + let memory = env.memory(); let url = unsafe { get_input_str!(memory, url, url_len) }; - let socket = wasi_try!(thread + let socket = wasi_try!(env .net() .ws_connect(url.as_str()) .map_err(net_error_into_wasi_err)); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let kind = Kind::Socket { socket: InodeSocket::new(InodeSocketKind::WebSocket(socket)), @@ -3835,7 +4032,7 @@ pub fn ws_connect( /// The body of the response can be streamed from the returned /// file handle pub fn http_request( - thread: &WasiThread, + env: &WasiEnv, url: WasmPtr, url_len: M::Offset, method: WasmPtr, @@ -3846,7 +4043,7 @@ pub fn http_request( ret_handles: WasmPtr<__wasi_http_handles_t, M>, ) -> __wasi_errno_t { debug!("wasi::http_request"); - let memory = thread.memory(); + let memory = env.memory(); let url = unsafe { get_input_str!(memory, url, url_len) }; let method = unsafe { get_input_str!(memory, method, method_len) }; let headers = unsafe { get_input_str!(memory, headers, headers_len) }; @@ -3857,7 +4054,7 @@ pub fn http_request( _ => return __WASI_EINVAL, }; - let socket = wasi_try!(thread + let socket = wasi_try!(env .net() .http_request(url.as_str(), method.as_str(), headers.as_str(), gzip) .map_err(net_error_into_wasi_err)); @@ -3880,7 +4077,7 @@ pub fn http_request( status: socket.status.clone(), }; - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let kind_req = Kind::Socket { socket: InodeSocket::new(InodeSocketKind::HttpRequest( @@ -3941,16 +4138,16 @@ pub fn http_request( /// * `status` - Pointer to a buffer that will be filled with the current /// status of this HTTP request pub fn http_status( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, status: WasmPtr<__wasi_http_status_t, M>, ) -> __wasi_errno_t { debug!("wasi::http_status"); - let memory = thread.memory(); + let memory = env.memory(); let ref_status = status.deref(memory); - let http_status = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + let http_status = wasi_try!(__sock_actor(env, sock, 0, |socket| { socket.http_status() })); @@ -3979,7 +4176,7 @@ pub fn http_status( /// * `token` - Access token used to authenticate with the network /// * `security` - Level of encryption to encapsulate the network connection with pub fn port_bridge( - thread: &WasiThread, + env: &WasiEnv, network: WasmPtr, network_len: M::Offset, token: WasmPtr, @@ -3987,7 +4184,7 @@ pub fn port_bridge( security: __wasi_streamsecurity_t, ) -> __wasi_errno_t { debug!("wasi::port_bridge"); - let memory = thread.memory(); + let memory = env.memory(); let network = unsafe { get_input_str!(memory, network, network_len) }; let token = unsafe { get_input_str!(memory, token, token_len) }; let security = match security { @@ -3998,7 +4195,7 @@ pub fn port_bridge( _ => return __WASI_EINVAL, }; - wasi_try!(thread + wasi_try!(env .net() .bridge(network.as_str(), token.as_str(), security) .map_err(net_error_into_wasi_err)); @@ -4007,17 +4204,17 @@ pub fn port_bridge( /// ### `port_unbridge()` /// Disconnects from a remote network -pub fn port_unbridge(thread: &WasiThread) -> __wasi_errno_t { +pub fn port_unbridge(env: &WasiEnv) -> __wasi_errno_t { debug!("wasi::port_unbridge"); - wasi_try!(thread.net().unbridge().map_err(net_error_into_wasi_err)); + wasi_try!(env.net().unbridge().map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_dhcp_acquire()` /// Acquires a set of IP addresses using DHCP -pub fn port_dhcp_acquire(thread: &WasiThread) -> __wasi_errno_t { +pub fn port_dhcp_acquire(env: &WasiEnv) -> __wasi_errno_t { debug!("wasi::port_dhcp_acquire"); - wasi_try!(thread.net().dhcp_acquire().map_err(net_error_into_wasi_err)); + wasi_try!(env.net().dhcp_acquire().map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } @@ -4028,13 +4225,13 @@ pub fn port_dhcp_acquire(thread: &WasiThread) -> __wasi_errno_t { /// /// * `addr` - Address to be added pub fn port_addr_add( - thread: &WasiThread, + env: &WasiEnv, ip: WasmPtr<__wasi_cidr_t, M>, ) -> __wasi_errno_t { debug!("wasi::port_addr_add"); - let memory = thread.memory(); + let memory = env.memory(); let cidr = wasi_try!(super::state::read_cidr(memory, ip)); - wasi_try!(thread + wasi_try!(env .net() .ip_add(cidr.ip, cidr.prefix) .map_err(net_error_into_wasi_err)); @@ -4048,33 +4245,33 @@ pub fn port_addr_add( /// /// * `addr` - Address to be removed pub fn port_addr_remove( - thread: &WasiThread, + env: &WasiEnv, ip: WasmPtr<__wasi_addr_t, M>, ) -> __wasi_errno_t { debug!("wasi::port_addr_remove"); - let memory = thread.memory(); + let memory = env.memory(); let ip = wasi_try!(super::state::read_ip(memory, ip)); - wasi_try!(thread.net().ip_remove(ip).map_err(net_error_into_wasi_err)); + wasi_try!(env.net().ip_remove(ip).map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_addr_clear()` /// Clears all the addresses on the local port -pub fn port_addr_clear(thread: &WasiThread) -> __wasi_errno_t { +pub fn port_addr_clear(env: &WasiEnv) -> __wasi_errno_t { debug!("wasi::port_addr_clear"); - wasi_try!(thread.net().ip_clear().map_err(net_error_into_wasi_err)); + wasi_try!(env.net().ip_clear().map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_mac()` /// Returns the MAC address of the local port pub fn port_mac( - thread: &WasiThread, + env: &WasiEnv, ret_mac: WasmPtr<__wasi_hardwareaddress_t, M>, ) -> __wasi_errno_t { debug!("wasi::port_mac"); - let memory = thread.memory(); - let mac = wasi_try!(thread.net().mac().map_err(net_error_into_wasi_err)); + let memory = env.memory(); + let mac = wasi_try!(env.net().mac().map_err(net_error_into_wasi_err)); let mac = __wasi_hardwareaddress_t { octs: mac }; wasi_try_mem!(ret_mac.write(memory, mac)); __WASI_ESUCCESS @@ -4094,18 +4291,18 @@ pub fn port_mac( /// /// The number of addresses returned. pub fn port_addr_list( - thread: &WasiThread, + env: &WasiEnv, addrs: WasmPtr<__wasi_cidr_t, M>, naddrs: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::port_addr_list"); - let memory = thread.memory(); + let memory = env.memory(); let max_addrs = wasi_try_mem!(naddrs.read(memory)); let max_addrs: u64 = wasi_try!(max_addrs.try_into().map_err(|_| __WASI_EOVERFLOW)); let ref_addrs = wasi_try_mem!(addrs.slice(memory, wasi_try!(to_offset::(max_addrs as usize)))); - let addrs = wasi_try!(thread.net().ip_list().map_err(net_error_into_wasi_err)); + let addrs = wasi_try!(env.net().ip_list().map_err(net_error_into_wasi_err)); let addrs_len: M::Offset = wasi_try!(addrs.len().try_into().map_err(|_| __WASI_EOVERFLOW)); wasi_try_mem!(naddrs.write(memory, addrs_len)); @@ -4128,31 +4325,28 @@ pub fn port_addr_list( /// /// * `addr` - Address of the default gateway pub fn port_gateway_set( - thread: &WasiThread, + env: &WasiEnv, ip: WasmPtr<__wasi_addr_t, M>, ) -> __wasi_errno_t { debug!("wasi::port_gateway_set"); - let memory = thread.memory(); + let memory = env.memory(); let ip = wasi_try!(super::state::read_ip(memory, ip)); - wasi_try!(thread - .net() - .gateway_set(ip) - .map_err(net_error_into_wasi_err)); + wasi_try!(env.net().gateway_set(ip).map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_route_add()` /// Adds a new route to the local port pub fn port_route_add( - thread: &WasiThread, + env: &WasiEnv, cidr: WasmPtr<__wasi_cidr_t, M>, via_router: WasmPtr<__wasi_addr_t, M>, preferred_until: WasmPtr<__wasi_option_timestamp_t, M>, expires_at: WasmPtr<__wasi_option_timestamp_t, M>, ) -> __wasi_errno_t { debug!("wasi::port_route_add"); - let memory = thread.memory(); + let memory = env.memory(); let cidr = wasi_try!(super::state::read_cidr(memory, cidr)); let via_router = wasi_try!(super::state::read_ip(memory, via_router)); let preferred_until = wasi_try_mem!(preferred_until.read(memory)); @@ -4168,7 +4362,7 @@ pub fn port_route_add( _ => return __WASI_EINVAL, }; - wasi_try!(thread + wasi_try!(env .net() .route_add(cidr, via_router, preferred_until, expires_at) .map_err(net_error_into_wasi_err)); @@ -4178,24 +4372,21 @@ pub fn port_route_add( /// ### `port_route_remove()` /// Removes an existing route from the local port pub fn port_route_remove( - thread: &WasiThread, + env: &WasiEnv, ip: WasmPtr<__wasi_addr_t, M>, ) -> __wasi_errno_t { debug!("wasi::port_route_remove"); - let memory = thread.memory(); + let memory = env.memory(); let ip = wasi_try!(super::state::read_ip(memory, ip)); - wasi_try!(thread - .net() - .route_remove(ip) - .map_err(net_error_into_wasi_err)); + wasi_try!(env.net().route_remove(ip).map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } /// ### `port_route_clear()` /// Clears all the routes in the local port -pub fn port_route_clear(thread: &WasiThread) -> __wasi_errno_t { +pub fn port_route_clear(env: &WasiEnv) -> __wasi_errno_t { debug!("wasi::port_route_clear"); - wasi_try!(thread.net().route_clear().map_err(net_error_into_wasi_err)); + wasi_try!(env.net().route_clear().map_err(net_error_into_wasi_err)); __WASI_ESUCCESS } @@ -4209,19 +4400,19 @@ pub fn port_route_clear(thread: &WasiThread) -> __wasi_errno_t { /// /// * `routes` - The buffer where routes will be stored pub fn port_route_list( - thread: &WasiThread, + env: &WasiEnv, routes: WasmPtr<__wasi_route_t, M>, nroutes: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::port_route_list"); - let memory = thread.memory(); + let memory = env.memory(); let nroutes = nroutes.deref(memory); let max_routes: usize = wasi_try!(wasi_try_mem!(nroutes.read()) .try_into() .map_err(|_| __WASI_EINVAL)); let ref_routes = wasi_try_mem!(routes.slice(memory, wasi_try!(to_offset::(max_routes)))); - let routes = wasi_try!(thread.net().route_list().map_err(net_error_into_wasi_err)); + let routes = wasi_try!(env.net().route_list().map_err(net_error_into_wasi_err)); let routes_len: M::Offset = wasi_try!(routes.len().try_into().map_err(|_| __WASI_EINVAL)); wasi_try_mem!(nroutes.write(routes_len)); @@ -4244,11 +4435,7 @@ pub fn port_route_list( /// ## Parameters /// /// * `how` - Which channels on the socket to shut down. -pub fn sock_shutdown( - thread: &WasiThread, - sock: __wasi_fd_t, - how: __wasi_sdflags_t, -) -> __wasi_errno_t { +pub fn sock_shutdown(env: &WasiEnv, sock: __wasi_fd_t, how: __wasi_sdflags_t) -> __wasi_errno_t { debug!("wasi::sock_shutdown"); let both = __WASI_SHUT_RD | __WASI_SHUT_WR; @@ -4260,7 +4447,7 @@ pub fn sock_shutdown( }; wasi_try!(__sock_actor_mut( - thread, + env, sock, __WASI_RIGHT_SOCK_SHUTDOWN, |socket| { socket.shutdown(how) } @@ -4272,13 +4459,13 @@ pub fn sock_shutdown( /// ### `sock_status()` /// Returns the current status of a socket pub fn sock_status( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ret_status: WasmPtr<__wasi_sockstatus_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_status"); - let status = wasi_try!(__sock_actor(thread, sock, 0, |socket| { socket.status() })); + let status = wasi_try!(__sock_actor(env, sock, 0, |socket| { socket.status() })); use super::state::WasiSocketStatus; let status = match status { @@ -4288,7 +4475,7 @@ pub fn sock_status( WasiSocketStatus::Failed => __WASI_SOCK_STATUS_FAILED, }; - wasi_try_mem!(ret_status.write(thread.memory(), status)); + wasi_try_mem!(ret_status.write(env.memory(), status)); __WASI_ESUCCESS } @@ -4305,17 +4492,15 @@ pub fn sock_status( /// /// * `fd` - Socket that the address is bound to pub fn sock_addr_local( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ret_addr: WasmPtr<__wasi_addr_port_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_addr_local"); - let addr = wasi_try!(__sock_actor(thread, sock, 0, |socket| { - socket.addr_local() - })); + let addr = wasi_try!(__sock_actor(env, sock, 0, |socket| { socket.addr_local() })); wasi_try!(super::state::write_ip_port( - thread.memory(), + env.memory(), ret_addr, addr.ip(), addr.port() @@ -4335,17 +4520,15 @@ pub fn sock_addr_local( /// /// * `fd` - Socket that the address is bound to pub fn sock_addr_peer( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ro_addr: WasmPtr<__wasi_addr_port_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_addr_peer"); - let addr = wasi_try!(__sock_actor(thread, sock, 0, |socket| { - socket.addr_peer() - })); + let addr = wasi_try!(__sock_actor(env, sock, 0, |socket| { socket.addr_peer() })); wasi_try!(super::state::write_ip_port( - thread.memory(), + env.memory(), ro_addr, addr.ip(), addr.port() @@ -4373,7 +4556,7 @@ pub fn sock_addr_peer( /// /// The file descriptor of the socket that has been opened. pub fn sock_open( - thread: &WasiThread, + env: &WasiEnv, af: __wasi_addressfamily_t, ty: __wasi_socktype_t, pt: __wasi_sockproto_t, @@ -4381,7 +4564,7 @@ pub fn sock_open( ) -> __wasi_errno_t { debug!("wasi::sock_open"); - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let kind = match ty { __WASI_SOCK_TYPE_STREAM | __WASI_SOCK_TYPE_DGRAM => Kind::Socket { @@ -4428,7 +4611,7 @@ pub fn sock_open( /// * `sockopt` - Socket option to be set /// * `flag` - Value to set the option to pub fn sock_set_opt_flag( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, flag: __wasi_bool_t, @@ -4442,7 +4625,7 @@ pub fn sock_set_opt_flag( }; let option: super::state::WasiSocketOption = opt.into(); - wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + wasi_try!(__sock_actor_mut(env, sock, 0, |socket| { socket.set_opt_flag(option, flag) })); __WASI_ESUCCESS @@ -4457,16 +4640,16 @@ pub fn sock_set_opt_flag( /// * `fd` - Socket descriptor /// * `sockopt` - Socket option to be retrieved pub fn sock_get_opt_flag( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_flag: WasmPtr<__wasi_bool_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_get_opt_flag(ty={})", opt); - let memory = thread.memory(); + let memory = env.memory(); let option: super::state::WasiSocketOption = opt.into(); - let flag = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + let flag = wasi_try!(__sock_actor(env, sock, 0, |socket| { socket.get_opt_flag(option) })); let flag = match flag { @@ -4488,14 +4671,14 @@ pub fn sock_get_opt_flag( /// * `sockopt` - Socket option to be set /// * `time` - Value to set the time to pub fn sock_set_opt_time( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, time: WasmPtr<__wasi_option_timestamp_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_set_opt_time(ty={})", opt); - let memory = thread.memory(); + let memory = env.memory(); let time = wasi_try_mem!(time.read(memory)); let time = match time.tag { __WASI_OPTION_NONE => None, @@ -4513,7 +4696,7 @@ pub fn sock_set_opt_time( }; let option: super::state::WasiSocketOption = opt.into(); - wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + wasi_try!(__sock_actor_mut(env, sock, 0, |socket| { socket.set_opt_time(ty, time) })); __WASI_ESUCCESS @@ -4527,13 +4710,13 @@ pub fn sock_set_opt_time( /// * `fd` - Socket descriptor /// * `sockopt` - Socket option to be retrieved pub fn sock_get_opt_time( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_time: WasmPtr<__wasi_option_timestamp_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_get_opt_time(ty={})", opt); - let memory = thread.memory(); + let memory = env.memory(); let ty = match opt { __WASI_SOCK_OPTION_RECV_TIMEOUT => wasmer_vnet::TimeType::ReadTimeout, @@ -4544,9 +4727,7 @@ pub fn sock_get_opt_time( _ => return __WASI_EINVAL, }; - let time = wasi_try!(__sock_actor(thread, sock, 0, |socket| { - socket.opt_time(ty) - })); + let time = wasi_try!(__sock_actor(env, sock, 0, |socket| { socket.opt_time(ty) })); let time = match time { None => __wasi_option_timestamp_t { tag: __WASI_OPTION_NONE, @@ -4573,7 +4754,7 @@ pub fn sock_get_opt_time( /// * `opt` - Socket option to be set /// * `size` - Buffer size pub fn sock_set_opt_size( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, size: __wasi_filesize_t, @@ -4590,7 +4771,7 @@ pub fn sock_set_opt_size( }; let option: super::state::WasiSocketOption = opt.into(); - wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + wasi_try!(__sock_actor_mut(env, sock, 0, |socket| { match opt { __WASI_SOCK_OPTION_RECV_BUF_SIZE => socket.set_recv_buf_size(size as usize), __WASI_SOCK_OPTION_SEND_BUF_SIZE => socket.set_send_buf_size(size as usize), @@ -4611,15 +4792,15 @@ pub fn sock_set_opt_size( /// * `fd` - Socket descriptor /// * `sockopt` - Socket option to be retrieved pub fn sock_get_opt_size( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_size: WasmPtr<__wasi_filesize_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_get_opt_size(ty={})", opt); - let memory = thread.memory(); + let memory = env.memory(); - let size = wasi_try!(__sock_actor(thread, sock, 0, |socket| { + let size = wasi_try!(__sock_actor(env, sock, 0, |socket| { match opt { __WASI_SOCK_OPTION_RECV_BUF_SIZE => { socket.recv_buf_size().map(|a| a as __wasi_filesize_t) @@ -4648,17 +4829,17 @@ pub fn sock_get_opt_size( /// * `multiaddr` - Multicast group to joined /// * `interface` - Interface that will join pub fn sock_join_multicast_v4( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip4_t, M>, iface: WasmPtr<__wasi_addr_ip4_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_join_multicast_v4"); - let memory = thread.memory(); + let memory = env.memory(); let multiaddr = wasi_try!(super::state::read_ip_v4(memory, multiaddr)); let iface = wasi_try!(super::state::read_ip_v4(memory, iface)); - wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + wasi_try!(__sock_actor_mut(env, sock, 0, |socket| { socket.join_multicast_v4(multiaddr, iface) })); __WASI_ESUCCESS @@ -4673,17 +4854,17 @@ pub fn sock_join_multicast_v4( /// * `multiaddr` - Multicast group to leave /// * `interface` - Interface that will left pub fn sock_leave_multicast_v4( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip4_t, M>, iface: WasmPtr<__wasi_addr_ip4_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_leave_multicast_v4"); - let memory = thread.memory(); + let memory = env.memory(); let multiaddr = wasi_try!(super::state::read_ip_v4(memory, multiaddr)); let iface = wasi_try!(super::state::read_ip_v4(memory, iface)); - wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + wasi_try!(__sock_actor_mut(env, sock, 0, |socket| { socket.leave_multicast_v4(multiaddr, iface) })); __WASI_ESUCCESS @@ -4698,16 +4879,16 @@ pub fn sock_leave_multicast_v4( /// * `multiaddr` - Multicast group to joined /// * `interface` - Interface that will join pub fn sock_join_multicast_v6( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip6_t, M>, iface: u32, ) -> __wasi_errno_t { debug!("wasi::sock_join_multicast_v6"); - let memory = thread.memory(); + let memory = env.memory(); let multiaddr = wasi_try!(super::state::read_ip_v6(memory, multiaddr)); - wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + wasi_try!(__sock_actor_mut(env, sock, 0, |socket| { socket.join_multicast_v6(multiaddr, iface) })); __WASI_ESUCCESS @@ -4722,16 +4903,16 @@ pub fn sock_join_multicast_v6( /// * `multiaddr` - Multicast group to leave /// * `interface` - Interface that will left pub fn sock_leave_multicast_v6( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip6_t, M>, iface: u32, ) -> __wasi_errno_t { debug!("wasi::sock_leave_multicast_v6"); - let memory = thread.memory(); + let memory = env.memory(); let multiaddr = wasi_try!(super::state::read_ip_v6(memory, multiaddr)); - wasi_try!(__sock_actor_mut(thread, sock, 0, |socket| { + wasi_try!(__sock_actor_mut(env, sock, 0, |socket| { socket.leave_multicast_v6(multiaddr, iface) })); __WASI_ESUCCESS @@ -4746,19 +4927,19 @@ pub fn sock_leave_multicast_v6( /// * `fd` - File descriptor of the socket to be bind /// * `addr` - Address to bind the socket to pub fn sock_bind( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, addr: WasmPtr<__wasi_addr_port_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_bind"); - let addr = wasi_try!(super::state::read_ip_port(thread.memory(), addr)); + let addr = wasi_try!(super::state::read_ip_port(env.memory(), addr)); let addr = SocketAddr::new(addr.0, addr.1); wasi_try!(__sock_upgrade( - thread, + env, sock, __WASI_RIGHT_SOCK_BIND, - |socket| { socket.bind(thread.net(), addr) } + |socket| { socket.bind(env.net(), addr) } )); __WASI_ESUCCESS } @@ -4776,7 +4957,7 @@ pub fn sock_bind( /// * `fd` - File descriptor of the socket to be bind /// * `backlog` - Maximum size of the queue for pending connections pub fn sock_listen( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, backlog: M::Offset, ) -> __wasi_errno_t { @@ -4784,10 +4965,10 @@ pub fn sock_listen( let backlog: usize = wasi_try!(backlog.try_into().map_err(|_| __WASI_EINVAL)); wasi_try!(__sock_upgrade( - thread, + env, sock, __WASI_RIGHT_SOCK_BIND, - |socket| { socket.listen(thread.net(), backlog) } + |socket| { socket.listen(env.net(), backlog) } )); __WASI_ESUCCESS } @@ -4805,7 +4986,7 @@ pub fn sock_listen( /// /// New socket connection pub fn sock_accept( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, fd_flags: __wasi_fdflags_t, ro_fd: WasmPtr<__wasi_fd_t, M>, @@ -4815,10 +4996,10 @@ pub fn sock_accept( let (child, addr) = { let mut ret; - let (_, state) = thread.get_memory_and_wasi_state(0); + let (_, state) = env.get_memory_and_wasi_state(0); loop { wasi_try_ok!( - match __sock_actor(thread, sock, __WASI_RIGHT_SOCK_ACCEPT, |socket| socket + match __sock_actor(env, sock, __WASI_RIGHT_SOCK_ACCEPT, |socket| socket .accept_timeout(fd_flags, Duration::from_millis(5))) { Ok(a) => { @@ -4826,11 +5007,11 @@ pub fn sock_accept( break; } Err(__WASI_ETIMEDOUT) => { - thread.yield_now()?; + env.yield_now()?; continue; } Err(__WASI_EAGAIN) => { - thread.sleep(Duration::from_millis(5))?; + env.sleep(Duration::from_millis(5))?; continue; } Err(err) => Err(err), @@ -4840,7 +5021,7 @@ pub fn sock_accept( ret }; - let (memory, state, mut inodes) = thread.get_memory_and_wasi_state_and_inodes_mut(0); + let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); let kind = Kind::Socket { socket: InodeSocket::new(InodeSocketKind::TcpStream(child)), @@ -4879,19 +5060,19 @@ pub fn sock_accept( /// * `fd` - Socket descriptor /// * `addr` - Address of the socket to connect to pub fn sock_connect( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, addr: WasmPtr<__wasi_addr_port_t, M>, ) -> __wasi_errno_t { debug!("wasi::sock_connect"); - let addr = wasi_try!(super::state::read_ip_port(thread.memory(), addr)); + let addr = wasi_try!(super::state::read_ip_port(env.memory(), addr)); let addr = SocketAddr::new(addr.0, addr.1); wasi_try!(__sock_upgrade( - thread, + env, sock, __WASI_RIGHT_SOCK_CONNECT, - |socket| { socket.connect(thread.net(), addr) } + |socket| { socket.connect(env.net(), addr) } )); __WASI_ESUCCESS } @@ -4910,7 +5091,7 @@ pub fn sock_connect( /// /// Number of bytes stored in ri_data and message flags. pub fn sock_recv( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ri_data: WasmPtr<__wasi_iovec_t, M>, ri_data_len: M::Offset, @@ -4920,11 +5101,11 @@ pub fn sock_recv( ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::sock_recv"); - let memory = thread.memory(); + let memory = env.memory(); let iovs_arr = wasi_try_mem_ok!(ri_data.slice(memory, ri_data_len)); let bytes_read = wasi_try_ok!(__sock_actor_mut( - thread, + env, sock, __WASI_RIGHT_SOCK_RECV, |socket| { socket.recv(memory, iovs_arr) } @@ -4951,7 +5132,7 @@ pub fn sock_recv( /// /// Number of bytes stored in ri_data and message flags. pub fn sock_recv_from( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ri_data: WasmPtr<__wasi_iovec_t, M>, ri_data_len: M::Offset, @@ -4962,11 +5143,11 @@ pub fn sock_recv_from( ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::sock_recv_from"); - let memory = thread.memory(); + let memory = env.memory(); let iovs_arr = wasi_try_mem_ok!(ri_data.slice(memory, ri_data_len)); let bytes_read = wasi_try_ok!(__sock_actor_mut( - thread, + env, sock, __WASI_RIGHT_SOCK_RECV_FROM, |socket| { socket.recv_from(memory, iovs_arr, ro_addr) } @@ -4993,7 +5174,7 @@ pub fn sock_recv_from( /// /// Number of bytes transmitted. pub fn sock_send( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, si_data: WasmPtr<__wasi_ciovec_t, M>, si_data_len: M::Offset, @@ -5002,11 +5183,11 @@ pub fn sock_send( ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::sock_send"); - let memory = thread.memory(); + let memory = env.memory(); let iovs_arr = wasi_try_mem_ok!(si_data.slice(memory, si_data_len)); let bytes_written = wasi_try_ok!(__sock_actor_mut( - thread, + env, sock, __WASI_RIGHT_SOCK_SEND, |socket| { socket.send(memory, iovs_arr) } @@ -5034,7 +5215,7 @@ pub fn sock_send( /// /// Number of bytes transmitted. pub fn sock_send_to( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, si_data: WasmPtr<__wasi_ciovec_t, M>, si_data_len: M::Offset, @@ -5044,11 +5225,11 @@ pub fn sock_send_to( ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::sock_send_to"); - let memory = thread.memory(); + let memory = env.memory(); let iovs_arr = wasi_try_mem_ok!(si_data.slice(memory, si_data_len)); let bytes_written = wasi_try_ok!(__sock_actor_mut( - thread, + env, sock, __WASI_RIGHT_SOCK_SEND_TO, |socket| { socket.send_to::(memory, iovs_arr, addr) } @@ -5074,7 +5255,7 @@ pub fn sock_send_to( /// /// Number of bytes transmitted. pub unsafe fn sock_send_file( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, in_fd: __wasi_fd_t, offset: __wasi_filesize_t, @@ -5082,7 +5263,7 @@ pub unsafe fn sock_send_file( ret_sent: WasmPtr<__wasi_filesize_t, M>, ) -> Result<__wasi_errno_t, WasiError> { debug!("wasi::send_file"); - let (memory, state, inodes) = thread.get_memory_and_wasi_state_and_inodes(0); + let (memory, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); // Set the offset of the file { @@ -5105,7 +5286,7 @@ pub unsafe fn sock_send_file( inodes .stdin_mut(&state.fs.fd_map) .map_err(fs_error_into_wasi_err), - thread + env ); if let Some(ref mut stdin) = guard.deref_mut() { wasi_try_ok!(stdin.read(&mut buf).map_err(map_io_err)) @@ -5133,7 +5314,7 @@ pub unsafe fn sock_send_file( handle .seek(std::io::SeekFrom::Start(offset as u64)) .map_err(map_io_err), - thread + env ); wasi_try_ok!(handle.read(&mut buf).map_err(map_io_err)) } else { @@ -5171,7 +5352,7 @@ pub unsafe fn sock_send_file( // Write it down to the socket let bytes_written = wasi_try_ok!(__sock_actor_mut( - thread, + env, sock, __WASI_RIGHT_SOCK_SEND, |socket| { @@ -5206,7 +5387,7 @@ pub unsafe fn sock_send_file( /// /// The number of IP addresses returned during the DNS resolution. pub fn resolve( - thread: &WasiThread, + env: &WasiEnv, host: WasmPtr, host_len: M::Offset, port: u16, @@ -5217,13 +5398,13 @@ pub fn resolve( debug!("wasi::resolve"); let naddrs: usize = wasi_try!(naddrs.try_into().map_err(|_| __WASI_EINVAL)); - let memory = thread.memory(); + let memory = env.memory(); let host_str = unsafe { get_input_str!(memory, host, host_len) }; let addrs = wasi_try_mem!(addrs.slice(memory, wasi_try!(to_offset::(naddrs)))); let port = if port > 0 { Some(port) } else { None }; - let found_ips = wasi_try!(thread + let found_ips = wasi_try!(env .net() .resolve(host_str.as_str(), port, None) .map_err(net_error_into_wasi_err)); diff --git a/lib/wasi/src/syscalls/wasi.rs b/lib/wasi/src/syscalls/wasi.rs index bed579502fe..b7d1c28edc4 100644 --- a/lib/wasi/src/syscalls/wasi.rs +++ b/lib/wasi/src/syscalls/wasi.rs @@ -1,5 +1,5 @@ #![deny(dead_code)] -use crate::{WasiError, WasiState, WasiThread}; +use crate::{WasiEnv, WasiError, WasiState, WasiThread}; use wasmer::{Memory, Memory32, MemorySize, WasmPtr, WasmSlice}; use wasmer_wasi_types::*; @@ -7,254 +7,250 @@ type MemoryType = Memory32; type MemoryOffset = u32; pub(crate) fn args_get( - thread: &WasiThread, + env: &WasiEnv, argv: WasmPtr, MemoryType>, argv_buf: WasmPtr, ) -> __wasi_errno_t { - super::args_get::(thread, argv, argv_buf) + super::args_get::(env, argv, argv_buf) } pub(crate) fn args_sizes_get( - thread: &WasiThread, + env: &WasiEnv, argc: WasmPtr, argv_buf_size: WasmPtr, ) -> __wasi_errno_t { - super::args_sizes_get::(thread, argc, argv_buf_size) + super::args_sizes_get::(env, argc, argv_buf_size) } pub(crate) fn clock_res_get( - thread: &WasiThread, + env: &WasiEnv, clock_id: __wasi_clockid_t, resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::clock_res_get::(thread, clock_id, resolution) + super::clock_res_get::(env, clock_id, resolution) } pub(crate) fn clock_time_get( - thread: &WasiThread, + env: &WasiEnv, clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, time: WasmPtr<__wasi_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::clock_time_get::(thread, clock_id, precision, time) + super::clock_time_get::(env, clock_id, precision, time) } pub(crate) fn environ_get( - thread: &WasiThread, + env: &WasiEnv, environ: WasmPtr, MemoryType>, environ_buf: WasmPtr, ) -> __wasi_errno_t { - super::environ_get::(thread, environ, environ_buf) + super::environ_get::(env, environ, environ_buf) } pub(crate) fn environ_sizes_get( - thread: &WasiThread, + env: &WasiEnv, environ_count: WasmPtr, environ_buf_size: WasmPtr, ) -> __wasi_errno_t { - super::environ_sizes_get::(thread, environ_count, environ_buf_size) + super::environ_sizes_get::(env, environ_count, environ_buf_size) } pub(crate) fn fd_advise( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, advice: __wasi_advice_t, ) -> __wasi_errno_t { - super::fd_advise(thread, fd, offset, len, advice) + super::fd_advise(env, fd, offset, len, advice) } pub(crate) fn fd_allocate( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, ) -> __wasi_errno_t { - super::fd_allocate(thread, fd, offset, len) + super::fd_allocate(env, fd, offset, len) } -pub(crate) fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(thread, fd) +pub(crate) fn fd_close(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_close(env, fd) } -pub(crate) fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(thread, fd) +pub(crate) fn fd_datasync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_datasync(env, fd) } pub(crate) fn fd_fdstat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_fdstat_get::(thread, fd, buf_ptr) + super::fd_fdstat_get::(env, fd, buf_ptr) } pub(crate) fn fd_fdstat_set_flags( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_fdflags_t, ) -> __wasi_errno_t { - super::fd_fdstat_set_flags(thread, fd, flags) + super::fd_fdstat_set_flags(env, fd, flags) } pub(crate) fn fd_fdstat_set_rights( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, fs_rights_base: __wasi_rights_t, fs_rights_inheriting: __wasi_rights_t, ) -> __wasi_errno_t { - super::fd_fdstat_set_rights(thread, fd, fs_rights_base, fs_rights_inheriting) + super::fd_fdstat_set_rights(env, fd, fs_rights_base, fs_rights_inheriting) } pub(crate) fn fd_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr<__wasi_filestat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_filestat_get::(thread, fd, buf) + super::fd_filestat_get::(env, fd, buf) } pub(crate) fn fd_filestat_set_size( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, st_size: __wasi_filesize_t, ) -> __wasi_errno_t { - super::fd_filestat_set_size(thread, fd, st_size) + super::fd_filestat_set_size(env, fd, st_size) } pub(crate) fn fd_filestat_set_times( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, st_atim: __wasi_timestamp_t, st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { - super::fd_filestat_set_times(thread, fd, st_atim, st_mtim, fst_flags) + super::fd_filestat_set_times(env, fd, st_atim, st_mtim, fst_flags) } pub(crate) fn fd_pread( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t, MemoryType>, iovs_len: MemoryOffset, offset: __wasi_filesize_t, nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(thread, fd, iovs, iovs_len, offset, nread) + super::fd_pread::(env, fd, iovs, iovs_len, offset, nread) } pub(crate) fn fd_prestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr<__wasi_prestat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_prestat_get::(thread, fd, buf) + super::fd_prestat_get::(env, fd, buf) } pub(crate) fn fd_prestat_dir_name( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::fd_prestat_dir_name::(thread, fd, path, path_len) + super::fd_prestat_dir_name::(env, fd, path, path_len) } pub(crate) fn fd_pwrite( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, iovs_len: MemoryOffset, offset: __wasi_filesize_t, nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(thread, fd, iovs, iovs_len, offset, nwritten) + super::fd_pwrite::(env, fd, iovs, iovs_len, offset, nwritten) } pub(crate) fn fd_read( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t, MemoryType>, iovs_len: MemoryOffset, nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(thread, fd, iovs, iovs_len, nread) + super::fd_read::(env, fd, iovs, iovs_len, nread) } pub(crate) fn fd_readdir( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr, buf_len: MemoryOffset, cookie: __wasi_dircookie_t, bufused: WasmPtr, ) -> __wasi_errno_t { - super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) + super::fd_readdir::(env, fd, buf, buf_len, cookie, bufused) } -pub(crate) fn fd_renumber( - thread: &WasiThread, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(thread, from, to) +pub(crate) fn fd_renumber(env: &WasiEnv, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { + super::fd_renumber(env, from, to) } pub(crate) fn fd_seek( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filedelta_t, whence: __wasi_whence_t, newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(thread, fd, offset, whence, newoffset) + super::fd_seek::(env, fd, offset, whence, newoffset) } -pub(crate) fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(thread, fd) +pub(crate) fn fd_sync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_sync(env, fd) } pub(crate) fn fd_tell( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_tell::(thread, fd, offset) + super::fd_tell::(env, fd, offset) } pub(crate) fn fd_write( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, iovs_len: MemoryOffset, nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(thread, fd, iovs, iovs_len, nwritten) + super::fd_write::(env, fd, iovs, iovs_len, nwritten) } pub(crate) fn path_create_directory( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_create_directory::(thread, fd, path, path_len) + super::path_create_directory::(env, fd, path, path_len) } pub(crate) fn path_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, path_len: MemoryOffset, buf: WasmPtr<__wasi_filestat_t, MemoryType>, ) -> __wasi_errno_t { - super::path_filestat_get::(thread, fd, flags, path, path_len, buf) + super::path_filestat_get::(env, fd, flags, path, path_len, buf) } pub(crate) fn path_filestat_set_times( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, @@ -264,12 +260,12 @@ pub(crate) fn path_filestat_set_times( fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { super::path_filestat_set_times::( - thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, + env, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, ) } pub(crate) fn path_link( - thread: &WasiThread, + env: &WasiEnv, old_fd: __wasi_fd_t, old_flags: __wasi_lookupflags_t, old_path: WasmPtr, @@ -279,7 +275,7 @@ pub(crate) fn path_link( new_path_len: MemoryOffset, ) -> __wasi_errno_t { super::path_link::( - thread, + env, old_fd, old_flags, old_path, @@ -291,7 +287,7 @@ pub(crate) fn path_link( } pub(crate) fn path_open( - thread: &WasiThread, + env: &WasiEnv, dirfd: __wasi_fd_t, dirflags: __wasi_lookupflags_t, path: WasmPtr, @@ -303,7 +299,7 @@ pub(crate) fn path_open( fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { super::path_open::( - thread, + env, dirfd, dirflags, path, @@ -317,7 +313,7 @@ pub(crate) fn path_open( } pub(crate) fn path_readlink( - thread: &WasiThread, + env: &WasiEnv, dir_fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, @@ -325,20 +321,20 @@ pub(crate) fn path_readlink( buf_len: MemoryOffset, buf_used: WasmPtr, ) -> __wasi_errno_t { - super::path_readlink::(thread, dir_fd, path, path_len, buf, buf_len, buf_used) + super::path_readlink::(env, dir_fd, path, path_len, buf, buf_len, buf_used) } pub(crate) fn path_remove_directory( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_remove_directory::(thread, fd, path, path_len) + super::path_remove_directory::(env, fd, path, path_len) } pub(crate) fn path_rename( - thread: &WasiThread, + env: &WasiEnv, old_fd: __wasi_fd_t, old_path: WasmPtr, old_path_len: MemoryOffset, @@ -347,7 +343,7 @@ pub(crate) fn path_rename( new_path_len: MemoryOffset, ) -> __wasi_errno_t { super::path_rename::( - thread, + env, old_fd, old_path, old_path_len, @@ -358,57 +354,57 @@ pub(crate) fn path_rename( } pub(crate) fn path_symlink( - thread: &WasiThread, + env: &WasiEnv, old_path: WasmPtr, old_path_len: MemoryOffset, fd: __wasi_fd_t, new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_symlink::(thread, old_path, old_path_len, fd, new_path, new_path_len) + super::path_symlink::(env, old_path, old_path_len, fd, new_path, new_path_len) } pub(crate) fn path_unlink_file( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_unlink_file::(thread, fd, path, path_len) + super::path_unlink_file::(env, fd, path, path_len) } pub(crate) fn poll_oneoff( - thread: &WasiThread, + env: &WasiEnv, in_: WasmPtr<__wasi_subscription_t, MemoryType>, out_: WasmPtr<__wasi_event_t, MemoryType>, nsubscriptions: MemoryOffset, nevents: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(thread, in_, out_, nsubscriptions, nevents) + super::poll_oneoff::(env, in_, out_, nsubscriptions, nevents) } -pub(crate) fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { - super::proc_exit(thread, code) +pub(crate) fn proc_exit(env: &WasiEnv, code: __wasi_exitcode_t) -> Result<(), WasiError> { + super::proc_exit(env, code) } -pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(thread, sig) +pub(crate) fn proc_raise(env: &WasiEnv, sig: __wasi_signal_t) -> __wasi_errno_t { + super::proc_raise(env, sig) } pub(crate) fn random_get( - thread: &WasiThread, + env: &WasiEnv, buf: WasmPtr, buf_len: MemoryOffset, ) -> __wasi_errno_t { - super::random_get::(thread, buf, buf_len) + super::random_get::(env, buf, buf_len) } -pub(crate) fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(thread) +pub(crate) fn sched_yield(env: &WasiEnv) -> Result<__wasi_errno_t, WasiError> { + super::sched_yield(env) } pub(crate) fn sock_recv( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, ri_data_len: MemoryOffset, @@ -417,7 +413,7 @@ pub(crate) fn sock_recv( ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { super::sock_recv::( - thread, + env, sock, ri_data, ri_data_len, @@ -428,20 +424,20 @@ pub(crate) fn sock_recv( } pub(crate) fn sock_send( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, si_data_len: MemoryOffset, si_flags: __wasi_siflags_t, ret_data_len: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(thread, sock, si_data, si_data_len, si_flags, ret_data_len) + super::sock_send::(env, sock, si_data, si_data_len, si_flags, ret_data_len) } pub(crate) fn sock_shutdown( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, how: __wasi_sdflags_t, ) -> __wasi_errno_t { - super::sock_shutdown(thread, sock, how) + super::sock_shutdown(env, sock, how) } diff --git a/lib/wasi/src/syscalls/wasix32.rs b/lib/wasi/src/syscalls/wasix32.rs index 30e50560df6..557e5c2089a 100644 --- a/lib/wasi/src/syscalls/wasix32.rs +++ b/lib/wasi/src/syscalls/wasix32.rs @@ -1,5 +1,5 @@ #![deny(dead_code)] -use crate::{WasiError, WasiState, WasiThread}; +use crate::{WasiEnv, WasiError, WasiState, WasiThread}; use wasmer::{Memory, Memory32, MemorySize, WasmPtr, WasmSlice}; use wasmer_wasi_types::*; @@ -7,254 +7,250 @@ type MemoryType = Memory32; type MemoryOffset = u32; pub(crate) fn args_get( - thread: &WasiThread, + env: &WasiEnv, argv: WasmPtr, MemoryType>, argv_buf: WasmPtr, ) -> __wasi_errno_t { - super::args_get::(thread, argv, argv_buf) + super::args_get::(env, argv, argv_buf) } pub(crate) fn args_sizes_get( - thread: &WasiThread, + env: &WasiEnv, argc: WasmPtr, argv_buf_size: WasmPtr, ) -> __wasi_errno_t { - super::args_sizes_get::(thread, argc, argv_buf_size) + super::args_sizes_get::(env, argc, argv_buf_size) } pub(crate) fn clock_res_get( - thread: &WasiThread, + env: &WasiEnv, clock_id: __wasi_clockid_t, resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::clock_res_get::(thread, clock_id, resolution) + super::clock_res_get::(env, clock_id, resolution) } pub(crate) fn clock_time_get( - thread: &WasiThread, + env: &WasiEnv, clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, time: WasmPtr<__wasi_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::clock_time_get::(thread, clock_id, precision, time) + super::clock_time_get::(env, clock_id, precision, time) } pub(crate) fn environ_get( - thread: &WasiThread, + env: &WasiEnv, environ: WasmPtr, MemoryType>, environ_buf: WasmPtr, ) -> __wasi_errno_t { - super::environ_get::(thread, environ, environ_buf) + super::environ_get::(env, environ, environ_buf) } pub(crate) fn environ_sizes_get( - thread: &WasiThread, + env: &WasiEnv, environ_count: WasmPtr, environ_buf_size: WasmPtr, ) -> __wasi_errno_t { - super::environ_sizes_get::(thread, environ_count, environ_buf_size) + super::environ_sizes_get::(env, environ_count, environ_buf_size) } pub(crate) fn fd_advise( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, advice: __wasi_advice_t, ) -> __wasi_errno_t { - super::fd_advise(thread, fd, offset, len, advice) + super::fd_advise(env, fd, offset, len, advice) } pub(crate) fn fd_allocate( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, ) -> __wasi_errno_t { - super::fd_allocate(thread, fd, offset, len) + super::fd_allocate(env, fd, offset, len) } -pub(crate) fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(thread, fd) +pub(crate) fn fd_close(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_close(env, fd) } -pub(crate) fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(thread, fd) +pub(crate) fn fd_datasync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_datasync(env, fd) } pub(crate) fn fd_fdstat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_fdstat_get::(thread, fd, buf_ptr) + super::fd_fdstat_get::(env, fd, buf_ptr) } pub(crate) fn fd_fdstat_set_flags( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_fdflags_t, ) -> __wasi_errno_t { - super::fd_fdstat_set_flags(thread, fd, flags) + super::fd_fdstat_set_flags(env, fd, flags) } pub(crate) fn fd_fdstat_set_rights( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, fs_rights_base: __wasi_rights_t, fs_rights_inheriting: __wasi_rights_t, ) -> __wasi_errno_t { - super::fd_fdstat_set_rights(thread, fd, fs_rights_base, fs_rights_inheriting) + super::fd_fdstat_set_rights(env, fd, fs_rights_base, fs_rights_inheriting) } pub(crate) fn fd_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr<__wasi_filestat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_filestat_get::(thread, fd, buf) + super::fd_filestat_get::(env, fd, buf) } pub(crate) fn fd_filestat_set_size( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, st_size: __wasi_filesize_t, ) -> __wasi_errno_t { - super::fd_filestat_set_size(thread, fd, st_size) + super::fd_filestat_set_size(env, fd, st_size) } pub(crate) fn fd_filestat_set_times( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, st_atim: __wasi_timestamp_t, st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { - super::fd_filestat_set_times(thread, fd, st_atim, st_mtim, fst_flags) + super::fd_filestat_set_times(env, fd, st_atim, st_mtim, fst_flags) } pub(crate) fn fd_pread( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t, MemoryType>, iovs_len: MemoryOffset, offset: __wasi_filesize_t, nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(thread, fd, iovs, iovs_len, offset, nread) + super::fd_pread::(env, fd, iovs, iovs_len, offset, nread) } pub(crate) fn fd_prestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr<__wasi_prestat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_prestat_get::(thread, fd, buf) + super::fd_prestat_get::(env, fd, buf) } pub(crate) fn fd_prestat_dir_name( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::fd_prestat_dir_name::(thread, fd, path, path_len) + super::fd_prestat_dir_name::(env, fd, path, path_len) } pub(crate) fn fd_pwrite( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, iovs_len: MemoryOffset, offset: __wasi_filesize_t, nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(thread, fd, iovs, iovs_len, offset, nwritten) + super::fd_pwrite::(env, fd, iovs, iovs_len, offset, nwritten) } pub(crate) fn fd_read( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t, MemoryType>, iovs_len: MemoryOffset, nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(thread, fd, iovs, iovs_len, nread) + super::fd_read::(env, fd, iovs, iovs_len, nread) } pub(crate) fn fd_readdir( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr, buf_len: MemoryOffset, cookie: __wasi_dircookie_t, bufused: WasmPtr, ) -> __wasi_errno_t { - super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) + super::fd_readdir::(env, fd, buf, buf_len, cookie, bufused) } -pub(crate) fn fd_renumber( - thread: &WasiThread, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(thread, from, to) +pub(crate) fn fd_renumber(env: &WasiEnv, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { + super::fd_renumber(env, from, to) } pub(crate) fn fd_seek( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filedelta_t, whence: __wasi_whence_t, newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(thread, fd, offset, whence, newoffset) + super::fd_seek::(env, fd, offset, whence, newoffset) } -pub(crate) fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(thread, fd) +pub(crate) fn fd_sync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_sync(env, fd) } pub(crate) fn fd_tell( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_tell::(thread, fd, offset) + super::fd_tell::(env, fd, offset) } pub(crate) fn fd_write( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, iovs_len: MemoryOffset, nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(thread, fd, iovs, iovs_len, nwritten) + super::fd_write::(env, fd, iovs, iovs_len, nwritten) } pub(crate) fn path_create_directory( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_create_directory::(thread, fd, path, path_len) + super::path_create_directory::(env, fd, path, path_len) } pub(crate) fn path_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, path_len: MemoryOffset, buf: WasmPtr<__wasi_filestat_t, MemoryType>, ) -> __wasi_errno_t { - super::path_filestat_get::(thread, fd, flags, path, path_len, buf) + super::path_filestat_get::(env, fd, flags, path, path_len, buf) } pub(crate) fn path_filestat_set_times( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, @@ -264,12 +260,12 @@ pub(crate) fn path_filestat_set_times( fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { super::path_filestat_set_times::( - thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, + env, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, ) } pub(crate) fn path_link( - thread: &WasiThread, + env: &WasiEnv, old_fd: __wasi_fd_t, old_flags: __wasi_lookupflags_t, old_path: WasmPtr, @@ -279,7 +275,7 @@ pub(crate) fn path_link( new_path_len: MemoryOffset, ) -> __wasi_errno_t { super::path_link::( - thread, + env, old_fd, old_flags, old_path, @@ -291,7 +287,7 @@ pub(crate) fn path_link( } pub(crate) fn path_open( - thread: &WasiThread, + env: &WasiEnv, dirfd: __wasi_fd_t, dirflags: __wasi_lookupflags_t, path: WasmPtr, @@ -303,7 +299,7 @@ pub(crate) fn path_open( fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { super::path_open::( - thread, + env, dirfd, dirflags, path, @@ -317,7 +313,7 @@ pub(crate) fn path_open( } pub(crate) fn path_readlink( - thread: &WasiThread, + env: &WasiEnv, dir_fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, @@ -325,20 +321,20 @@ pub(crate) fn path_readlink( buf_len: MemoryOffset, buf_used: WasmPtr, ) -> __wasi_errno_t { - super::path_readlink::(thread, dir_fd, path, path_len, buf, buf_len, buf_used) + super::path_readlink::(env, dir_fd, path, path_len, buf, buf_len, buf_used) } pub(crate) fn path_remove_directory( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_remove_directory::(thread, fd, path, path_len) + super::path_remove_directory::(env, fd, path, path_len) } pub(crate) fn path_rename( - thread: &WasiThread, + env: &WasiEnv, old_fd: __wasi_fd_t, old_path: WasmPtr, old_path_len: MemoryOffset, @@ -347,7 +343,7 @@ pub(crate) fn path_rename( new_path_len: MemoryOffset, ) -> __wasi_errno_t { super::path_rename::( - thread, + env, old_fd, old_path, old_path_len, @@ -358,162 +354,159 @@ pub(crate) fn path_rename( } pub(crate) fn path_symlink( - thread: &WasiThread, + env: &WasiEnv, old_path: WasmPtr, old_path_len: MemoryOffset, fd: __wasi_fd_t, new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_symlink::(thread, old_path, old_path_len, fd, new_path, new_path_len) + super::path_symlink::(env, old_path, old_path_len, fd, new_path, new_path_len) } pub(crate) fn path_unlink_file( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_unlink_file::(thread, fd, path, path_len) + super::path_unlink_file::(env, fd, path, path_len) } pub(crate) fn poll_oneoff( - thread: &WasiThread, + env: &WasiEnv, in_: WasmPtr<__wasi_subscription_t, MemoryType>, out_: WasmPtr<__wasi_event_t, MemoryType>, nsubscriptions: MemoryOffset, nevents: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(thread, in_, out_, nsubscriptions, nevents) + super::poll_oneoff::(env, in_, out_, nsubscriptions, nevents) } -pub(crate) fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { - super::proc_exit(thread, code) +pub(crate) fn proc_exit(env: &WasiEnv, code: __wasi_exitcode_t) -> Result<(), WasiError> { + super::proc_exit(env, code) } -pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(thread, sig) +pub(crate) fn proc_raise(env: &WasiEnv, sig: __wasi_signal_t) -> __wasi_errno_t { + super::proc_raise(env, sig) } pub(crate) fn random_get( - thread: &WasiThread, + env: &WasiEnv, buf: WasmPtr, buf_len: MemoryOffset, ) -> __wasi_errno_t { - super::random_get::(thread, buf, buf_len) + super::random_get::(env, buf, buf_len) } pub(crate) fn fd_dup( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_dup::(thread, fd, ret_fd) + super::fd_dup::(env, fd, ret_fd) } pub(crate) fn fd_event( - thread: &WasiThread, + env: &WasiEnv, initial_val: u64, flags: __wasi_eventfdflags, ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_event(thread, initial_val, flags, ret_fd) + super::fd_event(env, initial_val, flags, ret_fd) } pub(crate) fn fd_pipe( - thread: &WasiThread, + env: &WasiEnv, ro_fd1: WasmPtr<__wasi_fd_t, MemoryType>, ro_fd2: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_pipe::(thread, ro_fd1, ro_fd2) + super::fd_pipe::(env, ro_fd1, ro_fd2) } pub(crate) fn tty_get( - thread: &WasiThread, + env: &WasiEnv, tty_state: WasmPtr<__wasi_tty_t, MemoryType>, ) -> __wasi_errno_t { - super::tty_get::(thread, tty_state) + super::tty_get::(env, tty_state) } pub(crate) fn tty_set( - thread: &WasiThread, + env: &WasiEnv, tty_state: WasmPtr<__wasi_tty_t, MemoryType>, ) -> __wasi_errno_t { - super::tty_set::(thread, tty_state) + super::tty_set::(env, tty_state) } pub(crate) fn getcwd( - thread: &WasiThread, + env: &WasiEnv, path: WasmPtr, path_len: WasmPtr, ) -> __wasi_errno_t { - super::getcwd::(thread, path, path_len) + super::getcwd::(env, path, path_len) } pub(crate) fn chdir( - thread: &WasiThread, + env: &WasiEnv, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::chdir::(thread, path, path_len) + super::chdir::(env, path, path_len) } pub(crate) fn thread_spawn( - thread: &WasiThread, + env: &WasiEnv, method: WasmPtr, method_len: MemoryOffset, user_data: u64, reactor: __wasi_bool_t, ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, ) -> __wasi_errno_t { - super::thread_spawn::(thread, method, method_len, user_data, reactor, ret_tid) + super::thread_spawn::(env, method, method_len, user_data, reactor, ret_tid) } pub(crate) fn thread_sleep( - thread: &WasiThread, + env: &WasiEnv, duration: __wasi_timestamp_t, ) -> Result<__wasi_errno_t, WasiError> { - super::thread_sleep(thread, duration) + super::thread_sleep(env, duration) } pub(crate) fn thread_id( - thread: &WasiThread, + env: &WasiEnv, ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, ) -> __wasi_errno_t { - super::thread_id::(thread, ret_tid) + super::thread_id::(env, ret_tid) } -pub(crate) fn thread_join(thread: &WasiThread, tid: __wasi_tid_t) -> __wasi_errno_t { - super::thread_join(thread, tid) +pub(crate) fn thread_join(env: &WasiEnv, tid: __wasi_tid_t) -> Result<__wasi_errno_t, WasiError> { + super::thread_join(env, tid) } pub(crate) fn thread_parallelism( - thread: &WasiThread, + env: &WasiEnv, ret_parallelism: WasmPtr, ) -> __wasi_errno_t { - super::thread_parallelism::(thread, ret_parallelism) + super::thread_parallelism::(env, ret_parallelism) } pub(crate) fn thread_exit( - thread: &WasiThread, + env: &WasiEnv, exitcode: __wasi_exitcode_t, ) -> Result<__wasi_errno_t, WasiError> { - super::thread_exit(thread, exitcode) + super::thread_exit(env, exitcode) } -pub(crate) fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(thread) +pub(crate) fn sched_yield(env: &WasiEnv) -> Result<__wasi_errno_t, WasiError> { + super::sched_yield(env) } -pub(crate) fn getpid( - thread: &WasiThread, - ret_pid: WasmPtr<__wasi_pid_t, MemoryType>, -) -> __wasi_errno_t { - super::getpid::(thread, ret_pid) +pub(crate) fn getpid(env: &WasiEnv, ret_pid: WasmPtr<__wasi_pid_t, MemoryType>) -> __wasi_errno_t { + super::getpid::(env, ret_pid) } -pub(crate) fn bus_spawn_local( - thread: &WasiThread, +pub(crate) fn process_spawn( + env: &WasiEnv, name: WasmPtr, name_len: MemoryOffset, chroot: __wasi_bool_t, @@ -527,9 +520,9 @@ pub(crate) fn bus_spawn_local( working_dir: WasmPtr, working_dir_len: MemoryOffset, ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, -) -> __wasi_errno_t { - super::bus_spawn_local::( - thread, +) -> __bus_errno_t { + super::process_spawn::( + env, name, name_len, chroot, @@ -546,56 +539,47 @@ pub(crate) fn bus_spawn_local( ) } -pub(crate) fn bus_spawn_remote( - thread: &WasiThread, +pub(crate) fn bus_open_local( + env: &WasiEnv, name: WasmPtr, name_len: MemoryOffset, - chroot: __wasi_bool_t, - args: WasmPtr, - args_len: MemoryOffset, - preopen: WasmPtr, - preopen_len: MemoryOffset, - working_dir: WasmPtr, - working_dir_len: MemoryOffset, - stdin: __wasi_stdiomode_t, - stdout: __wasi_stdiomode_t, - stderr: __wasi_stdiomode_t, + reuse: __wasi_bool_t, + ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, +) -> __bus_errno_t { + super::bus_open_local::(env, name, name_len, reuse, ret_bid) +} + +pub(crate) fn bus_open_remote( + env: &WasiEnv, + name: WasmPtr, + name_len: MemoryOffset, + reuse: __wasi_bool_t, instance: WasmPtr, instance_len: MemoryOffset, token: WasmPtr, token_len: MemoryOffset, - ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, -) -> __wasi_errno_t { - super::bus_spawn_remote::( - thread, + ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, +) -> __bus_errno_t { + super::bus_open_remote::( + env, name, name_len, - chroot, - args, - args_len, - preopen, - preopen_len, - working_dir, - working_dir_len, - stdin, - stdout, - stderr, + reuse, instance, instance_len, token, token_len, - ret_handles, + ret_bid, ) } -pub(crate) fn bus_close(thread: &WasiThread, bid: __wasi_bid_t) -> __wasi_errno_t { - super::bus_close(thread, bid) +pub(crate) fn bus_close(env: &WasiEnv, bid: __wasi_bid_t) -> __bus_errno_t { + super::bus_close(env, bid) } -pub(crate) fn bus_invoke( - thread: &WasiThread, +pub(crate) fn bus_call( + env: &WasiEnv, bid: __wasi_bid_t, - cid: WasmPtr<__wasi_option_cid_t, MemoryType>, keep_alive: __wasi_bool_t, topic: WasmPtr, topic_len: MemoryOffset, @@ -603,180 +587,165 @@ pub(crate) fn bus_invoke( buf: WasmPtr, buf_len: MemoryOffset, ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __wasi_errno_t { - super::bus_invoke::( - thread, bid, cid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, +) -> __bus_errno_t { + super::bus_call::( + env, bid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, ) } -pub(crate) fn bus_fault( - thread: &WasiThread, - cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __wasi_errno_t { - super::bus_fault(thread, cid, fault) -} - -pub(crate) fn bus_drop(thread: &WasiThread, cid: __wasi_cid_t) -> __wasi_errno_t { - super::bus_drop(thread, cid) -} - -pub(crate) fn bus_reply( - thread: &WasiThread, - cid: __wasi_cid_t, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::bus_reply::(thread, cid, format, buf, buf_len) -} - -pub(crate) fn bus_callback( - thread: &WasiThread, - cid: __wasi_cid_t, +pub(crate) fn bus_subcall( + env: &WasiEnv, + parent: __wasi_cid_t, + keep_alive: __wasi_bool_t, topic: WasmPtr, topic_len: MemoryOffset, format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::bus_callback::(thread, cid, topic, topic_len, format, buf, buf_len) -} - -pub(crate) fn bus_listen( - thread: &WasiThread, - parent: WasmPtr<__wasi_option_cid_t, MemoryType>, - topic: WasmPtr, - topic_len: MemoryOffset, -) -> __wasi_errno_t { - super::bus_listen::(thread, parent, topic, topic_len) + ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, +) -> __bus_errno_t { + super::bus_subcall::( + env, parent, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, + ) } pub(crate) fn bus_poll( - thread: &WasiThread, - bid: WasmPtr<__wasi_option_bid_t, MemoryType>, - timeout: WasmPtr<__wasi_timestamp_t, MemoryType>, + env: &WasiEnv, + timeout: __wasi_timestamp_t, events: WasmPtr, nevents: MemoryOffset, + malloc: WasmPtr, + malloc_len: MemoryOffset, ret_nevents: WasmPtr, -) -> __wasi_errno_t { - super::bus_poll::(thread, bid, timeout, events, nevents, ret_nevents) +) -> __bus_errno_t { + super::bus_poll::( + env, + timeout, + events, + nevents, + malloc, + malloc_len, + ret_nevents, + ) } -pub(crate) fn bus_poll_data( - thread: &WasiThread, - bid: WasmPtr<__wasi_option_bid_t, MemoryType>, - timeout: WasmPtr<__wasi_timestamp_t, MemoryType>, - topic: WasmPtr, - topic_len: MemoryOffset, +pub(crate) fn call_reply( + env: &WasiEnv, + cid: __wasi_cid_t, + format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: MemoryOffset, - ret_evt: WasmPtr<__wasi_busevent_data_t, MemoryType>, -) -> __wasi_errno_t { - super::bus_poll_data::( - thread, bid, timeout, topic, topic_len, buf, buf_len, ret_evt, - ) +) -> __bus_errno_t { + super::call_reply::(env, cid, format, buf, buf_len) +} + +pub(crate) fn call_fault(env: &WasiEnv, cid: __wasi_cid_t, fault: __bus_errno_t) -> __bus_errno_t { + super::call_fault(env, cid, fault) +} + +pub(crate) fn call_close(env: &WasiEnv, cid: __wasi_cid_t) -> __bus_errno_t { + super::call_close(env, cid) } pub(crate) fn port_bridge( - thread: &WasiThread, + env: &WasiEnv, network: WasmPtr, network_len: MemoryOffset, token: WasmPtr, token_len: MemoryOffset, security: __wasi_streamsecurity_t, ) -> __wasi_errno_t { - super::port_bridge::(thread, network, network_len, token, token_len, security) + super::port_bridge::(env, network, network_len, token, token_len, security) } -pub(crate) fn port_unbridge(thread: &WasiThread) -> __wasi_errno_t { - super::port_unbridge(thread) +pub(crate) fn port_unbridge(env: &WasiEnv) -> __wasi_errno_t { + super::port_unbridge(env) } -pub(crate) fn port_dhcp_acquire(thread: &WasiThread) -> __wasi_errno_t { - super::port_dhcp_acquire(thread) +pub(crate) fn port_dhcp_acquire(env: &WasiEnv) -> __wasi_errno_t { + super::port_dhcp_acquire(env) } pub(crate) fn port_addr_add( - thread: &WasiThread, + env: &WasiEnv, addr: WasmPtr<__wasi_cidr_t, MemoryType>, ) -> __wasi_errno_t { - super::port_addr_add::(thread, addr) + super::port_addr_add::(env, addr) } pub(crate) fn port_addr_remove( - thread: &WasiThread, + env: &WasiEnv, addr: WasmPtr<__wasi_addr_t, MemoryType>, ) -> __wasi_errno_t { - super::port_addr_remove::(thread, addr) + super::port_addr_remove::(env, addr) } -pub(crate) fn port_addr_clear(thread: &WasiThread) -> __wasi_errno_t { - super::port_addr_clear(thread) +pub(crate) fn port_addr_clear(env: &WasiEnv) -> __wasi_errno_t { + super::port_addr_clear(env) } pub(crate) fn port_addr_list( - thread: &WasiThread, + env: &WasiEnv, addrs: WasmPtr<__wasi_cidr_t, MemoryType>, naddrs: WasmPtr, ) -> __wasi_errno_t { - super::port_addr_list::(thread, addrs, naddrs) + super::port_addr_list::(env, addrs, naddrs) } pub(crate) fn port_mac( - thread: &WasiThread, + env: &WasiEnv, ret_mac: WasmPtr<__wasi_hardwareaddress_t, MemoryType>, ) -> __wasi_errno_t { - super::port_mac::(thread, ret_mac) + super::port_mac::(env, ret_mac) } pub(crate) fn port_gateway_set( - thread: &WasiThread, + env: &WasiEnv, ip: WasmPtr<__wasi_addr_t, MemoryType>, ) -> __wasi_errno_t { - super::port_gateway_set::(thread, ip) + super::port_gateway_set::(env, ip) } pub(crate) fn port_route_add( - thread: &WasiThread, + env: &WasiEnv, cidr: WasmPtr<__wasi_cidr_t, MemoryType>, via_router: WasmPtr<__wasi_addr_t, MemoryType>, preferred_until: WasmPtr<__wasi_option_timestamp_t, MemoryType>, expires_at: WasmPtr<__wasi_option_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::port_route_add::(thread, cidr, via_router, preferred_until, expires_at) + super::port_route_add::(env, cidr, via_router, preferred_until, expires_at) } pub(crate) fn port_route_remove( - thread: &WasiThread, + env: &WasiEnv, ip: WasmPtr<__wasi_addr_t, MemoryType>, ) -> __wasi_errno_t { - super::port_route_remove::(thread, ip) + super::port_route_remove::(env, ip) } -pub(crate) fn port_route_clear(thread: &WasiThread) -> __wasi_errno_t { - super::port_route_clear(thread) +pub(crate) fn port_route_clear(env: &WasiEnv) -> __wasi_errno_t { + super::port_route_clear(env) } pub(crate) fn port_route_list( - thread: &WasiThread, + env: &WasiEnv, routes: WasmPtr<__wasi_route_t, MemoryType>, nroutes: WasmPtr, ) -> __wasi_errno_t { - super::port_route_list::(thread, routes, nroutes) + super::port_route_list::(env, routes, nroutes) } pub(crate) fn ws_connect( - thread: &WasiThread, + env: &WasiEnv, url: WasmPtr, url_len: MemoryOffset, ret_sock: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::ws_connect::(thread, url, url_len, ret_sock) + super::ws_connect::(env, url, url_len, ret_sock) } pub(crate) fn http_request( - thread: &WasiThread, + env: &WasiEnv, url: WasmPtr, url_len: MemoryOffset, method: WasmPtr, @@ -787,7 +756,7 @@ pub(crate) fn http_request( ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, ) -> __wasi_errno_t { super::http_request::( - thread, + env, url, url_len, method, @@ -800,7 +769,7 @@ pub(crate) fn http_request( } pub(crate) fn http_status( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, status: WasmPtr<__wasi_http_status_t, MemoryType>, status_text: WasmPtr, @@ -808,169 +777,169 @@ pub(crate) fn http_status( headers: WasmPtr, headers_len: WasmPtr, ) -> __wasi_errno_t { - super::http_status::(thread, sock, status) + super::http_status::(env, sock, status) } pub(crate) fn sock_status( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_status::(thread, sock, ret_status) + super::sock_status::(env, sock, ret_status) } pub(crate) fn sock_addr_local( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ret_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_addr_local::(thread, sock, ret_addr) + super::sock_addr_local::(env, sock, ret_addr) } pub(crate) fn sock_addr_peer( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_addr_peer::(thread, sock, ro_addr) + super::sock_addr_peer::(env, sock, ro_addr) } pub(crate) fn sock_open( - thread: &WasiThread, + env: &WasiEnv, af: __wasi_addressfamily_t, ty: __wasi_socktype_t, pt: __wasi_sockproto_t, ro_sock: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_open::(thread, af, ty, pt, ro_sock) + super::sock_open::(env, af, ty, pt, ro_sock) } pub(crate) fn sock_set_opt_flag( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, flag: __wasi_bool_t, ) -> __wasi_errno_t { - super::sock_set_opt_flag(thread, sock, opt, flag) + super::sock_set_opt_flag(env, sock, opt, flag) } pub(crate) fn sock_get_opt_flag( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_flag: WasmPtr<__wasi_bool_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_get_opt_flag::(thread, sock, opt, ret_flag) + super::sock_get_opt_flag::(env, sock, opt, ret_flag) } pub fn sock_set_opt_time( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_set_opt_time(thread, sock, opt, time) + super::sock_set_opt_time(env, sock, opt, time) } pub fn sock_get_opt_time( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_get_opt_time(thread, sock, opt, ret_time) + super::sock_get_opt_time(env, sock, opt, ret_time) } pub fn sock_set_opt_size( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, size: __wasi_filesize_t, ) -> __wasi_errno_t { - super::sock_set_opt_size(thread, sock, opt, size) + super::sock_set_opt_size(env, sock, opt, size) } pub fn sock_get_opt_size( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_size: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_get_opt_size(thread, sock, opt, ret_size) + super::sock_get_opt_size(env, sock, opt, ret_size) } pub(crate) fn sock_join_multicast_v4( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_join_multicast_v4::(thread, sock, multiaddr, iface) + super::sock_join_multicast_v4::(env, sock, multiaddr, iface) } pub(crate) fn sock_leave_multicast_v4( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_leave_multicast_v4::(thread, sock, multiaddr, iface) + super::sock_leave_multicast_v4::(env, sock, multiaddr, iface) } pub(crate) fn sock_join_multicast_v6( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, iface: u32, ) -> __wasi_errno_t { - super::sock_join_multicast_v6::(thread, sock, multiaddr, iface) + super::sock_join_multicast_v6::(env, sock, multiaddr, iface) } pub(crate) fn sock_leave_multicast_v6( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, iface: u32, ) -> __wasi_errno_t { - super::sock_leave_multicast_v6::(thread, sock, multiaddr, iface) + super::sock_leave_multicast_v6::(env, sock, multiaddr, iface) } pub(crate) fn sock_bind( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_bind::(thread, sock, addr) + super::sock_bind::(env, sock, addr) } pub(crate) fn sock_listen( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, backlog: MemoryOffset, ) -> __wasi_errno_t { - super::sock_listen::(thread, sock, backlog) + super::sock_listen::(env, sock, backlog) } pub(crate) fn sock_accept( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, fd_flags: __wasi_fdflags_t, ro_fd: WasmPtr<__wasi_fd_t, MemoryType>, ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_accept::(thread, sock, fd_flags, ro_fd, ro_addr) + super::sock_accept::(env, sock, fd_flags, ro_fd, ro_addr) } pub(crate) fn sock_connect( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_connect::(thread, sock, addr) + super::sock_connect::(env, sock, addr) } pub(crate) fn sock_recv( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, ri_data_len: MemoryOffset, @@ -979,7 +948,7 @@ pub(crate) fn sock_recv( ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { super::sock_recv::( - thread, + env, sock, ri_data, ri_data_len, @@ -990,7 +959,7 @@ pub(crate) fn sock_recv( } pub(crate) fn sock_recv_from( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, ri_data_len: MemoryOffset, @@ -1000,7 +969,7 @@ pub(crate) fn sock_recv_from( ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { super::sock_recv_from::( - thread, + env, sock, ri_data, ri_data_len, @@ -1012,18 +981,18 @@ pub(crate) fn sock_recv_from( } pub(crate) fn sock_send( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, si_data_len: MemoryOffset, si_flags: __wasi_siflags_t, ret_data_len: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(thread, sock, si_data, si_data_len, si_flags, ret_data_len) + super::sock_send::(env, sock, si_data, si_data_len, si_flags, ret_data_len) } pub(crate) fn sock_send_to( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, si_data_len: MemoryOffset, @@ -1032,7 +1001,7 @@ pub(crate) fn sock_send_to( ret_data_len: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { super::sock_send_to::( - thread, + env, sock, si_data, si_data_len, @@ -1043,26 +1012,26 @@ pub(crate) fn sock_send_to( } pub(crate) fn sock_send_file( - thread: &WasiThread, + env: &WasiEnv, out_fd: __wasi_fd_t, in_fd: __wasi_fd_t, offset: __wasi_filesize_t, count: __wasi_filesize_t, ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - unsafe { super::sock_send_file::(thread, out_fd, in_fd, offset, count, ret_sent) } + unsafe { super::sock_send_file::(env, out_fd, in_fd, offset, count, ret_sent) } } pub(crate) fn sock_shutdown( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, how: __wasi_sdflags_t, ) -> __wasi_errno_t { - super::sock_shutdown(thread, sock, how) + super::sock_shutdown(env, sock, how) } pub(crate) fn resolve( - thread: &WasiThread, + env: &WasiEnv, host: WasmPtr, host_len: MemoryOffset, port: u16, @@ -1070,5 +1039,5 @@ pub(crate) fn resolve( nips: MemoryOffset, ret_nips: WasmPtr, ) -> __wasi_errno_t { - super::resolve::(thread, host, host_len, port, ips, nips, ret_nips) + super::resolve::(env, host, host_len, port, ips, nips, ret_nips) } diff --git a/lib/wasi/src/syscalls/wasix64.rs b/lib/wasi/src/syscalls/wasix64.rs index 6bbd9abb4c7..e3ece1fb80d 100644 --- a/lib/wasi/src/syscalls/wasix64.rs +++ b/lib/wasi/src/syscalls/wasix64.rs @@ -1,5 +1,5 @@ #![deny(dead_code)] -use crate::{WasiError, WasiState, WasiThread}; +use crate::{WasiEnv, WasiError, WasiState, WasiThread}; use wasmer::{Memory, Memory64, MemorySize, WasmPtr, WasmSlice}; use wasmer_wasi_types::*; @@ -7,254 +7,250 @@ type MemoryType = Memory64; type MemoryOffset = u64; pub(crate) fn args_get( - thread: &WasiThread, + env: &WasiEnv, argv: WasmPtr, MemoryType>, argv_buf: WasmPtr, ) -> __wasi_errno_t { - super::args_get::(thread, argv, argv_buf) + super::args_get::(env, argv, argv_buf) } pub(crate) fn args_sizes_get( - thread: &WasiThread, + env: &WasiEnv, argc: WasmPtr, argv_buf_size: WasmPtr, ) -> __wasi_errno_t { - super::args_sizes_get::(thread, argc, argv_buf_size) + super::args_sizes_get::(env, argc, argv_buf_size) } pub(crate) fn clock_res_get( - thread: &WasiThread, + env: &WasiEnv, clock_id: __wasi_clockid_t, resolution: WasmPtr<__wasi_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::clock_res_get::(thread, clock_id, resolution) + super::clock_res_get::(env, clock_id, resolution) } pub(crate) fn clock_time_get( - thread: &WasiThread, + env: &WasiEnv, clock_id: __wasi_clockid_t, precision: __wasi_timestamp_t, time: WasmPtr<__wasi_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::clock_time_get::(thread, clock_id, precision, time) + super::clock_time_get::(env, clock_id, precision, time) } pub(crate) fn environ_get( - thread: &WasiThread, + env: &WasiEnv, environ: WasmPtr, MemoryType>, environ_buf: WasmPtr, ) -> __wasi_errno_t { - super::environ_get::(thread, environ, environ_buf) + super::environ_get::(env, environ, environ_buf) } pub(crate) fn environ_sizes_get( - thread: &WasiThread, + env: &WasiEnv, environ_count: WasmPtr, environ_buf_size: WasmPtr, ) -> __wasi_errno_t { - super::environ_sizes_get::(thread, environ_count, environ_buf_size) + super::environ_sizes_get::(env, environ_count, environ_buf_size) } pub(crate) fn fd_advise( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, advice: __wasi_advice_t, ) -> __wasi_errno_t { - super::fd_advise(thread, fd, offset, len, advice) + super::fd_advise(env, fd, offset, len, advice) } pub(crate) fn fd_allocate( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filesize_t, len: __wasi_filesize_t, ) -> __wasi_errno_t { - super::fd_allocate(thread, fd, offset, len) + super::fd_allocate(env, fd, offset, len) } -pub(crate) fn fd_close(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_close(thread, fd) +pub(crate) fn fd_close(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_close(env, fd) } -pub(crate) fn fd_datasync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_datasync(thread, fd) +pub(crate) fn fd_datasync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_datasync(env, fd) } pub(crate) fn fd_fdstat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf_ptr: WasmPtr<__wasi_fdstat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_fdstat_get::(thread, fd, buf_ptr) + super::fd_fdstat_get::(env, fd, buf_ptr) } pub(crate) fn fd_fdstat_set_flags( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_fdflags_t, ) -> __wasi_errno_t { - super::fd_fdstat_set_flags(thread, fd, flags) + super::fd_fdstat_set_flags(env, fd, flags) } pub(crate) fn fd_fdstat_set_rights( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, fs_rights_base: __wasi_rights_t, fs_rights_inheriting: __wasi_rights_t, ) -> __wasi_errno_t { - super::fd_fdstat_set_rights(thread, fd, fs_rights_base, fs_rights_inheriting) + super::fd_fdstat_set_rights(env, fd, fs_rights_base, fs_rights_inheriting) } pub(crate) fn fd_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr<__wasi_filestat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_filestat_get::(thread, fd, buf) + super::fd_filestat_get::(env, fd, buf) } pub(crate) fn fd_filestat_set_size( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, st_size: __wasi_filesize_t, ) -> __wasi_errno_t { - super::fd_filestat_set_size(thread, fd, st_size) + super::fd_filestat_set_size(env, fd, st_size) } pub(crate) fn fd_filestat_set_times( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, st_atim: __wasi_timestamp_t, st_mtim: __wasi_timestamp_t, fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { - super::fd_filestat_set_times(thread, fd, st_atim, st_mtim, fst_flags) + super::fd_filestat_set_times(env, fd, st_atim, st_mtim, fst_flags) } pub(crate) fn fd_pread( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t, MemoryType>, iovs_len: MemoryOffset, offset: __wasi_filesize_t, nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_pread::(thread, fd, iovs, iovs_len, offset, nread) + super::fd_pread::(env, fd, iovs, iovs_len, offset, nread) } pub(crate) fn fd_prestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr<__wasi_prestat_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_prestat_get::(thread, fd, buf) + super::fd_prestat_get::(env, fd, buf) } pub(crate) fn fd_prestat_dir_name( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::fd_prestat_dir_name::(thread, fd, path, path_len) + super::fd_prestat_dir_name::(env, fd, path, path_len) } pub(crate) fn fd_pwrite( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, iovs_len: MemoryOffset, offset: __wasi_filesize_t, nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_pwrite::(thread, fd, iovs, iovs_len, offset, nwritten) + super::fd_pwrite::(env, fd, iovs, iovs_len, offset, nwritten) } pub(crate) fn fd_read( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_iovec_t, MemoryType>, iovs_len: MemoryOffset, nread: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_read::(thread, fd, iovs, iovs_len, nread) + super::fd_read::(env, fd, iovs, iovs_len, nread) } pub(crate) fn fd_readdir( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, buf: WasmPtr, buf_len: MemoryOffset, cookie: __wasi_dircookie_t, bufused: WasmPtr, ) -> __wasi_errno_t { - super::fd_readdir::(thread, fd, buf, buf_len, cookie, bufused) + super::fd_readdir::(env, fd, buf, buf_len, cookie, bufused) } -pub(crate) fn fd_renumber( - thread: &WasiThread, - from: __wasi_fd_t, - to: __wasi_fd_t, -) -> __wasi_errno_t { - super::fd_renumber(thread, from, to) +pub(crate) fn fd_renumber(env: &WasiEnv, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_errno_t { + super::fd_renumber(env, from, to) } pub(crate) fn fd_seek( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: __wasi_filedelta_t, whence: __wasi_whence_t, newoffset: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_seek::(thread, fd, offset, whence, newoffset) + super::fd_seek::(env, fd, offset, whence, newoffset) } -pub(crate) fn fd_sync(thread: &WasiThread, fd: __wasi_fd_t) -> __wasi_errno_t { - super::fd_sync(thread, fd) +pub(crate) fn fd_sync(env: &WasiEnv, fd: __wasi_fd_t) -> __wasi_errno_t { + super::fd_sync(env, fd) } pub(crate) fn fd_tell( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, offset: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_tell::(thread, fd, offset) + super::fd_tell::(env, fd, offset) } pub(crate) fn fd_write( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, iovs: WasmPtr<__wasi_ciovec_t, MemoryType>, iovs_len: MemoryOffset, nwritten: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::fd_write::(thread, fd, iovs, iovs_len, nwritten) + super::fd_write::(env, fd, iovs, iovs_len, nwritten) } pub(crate) fn path_create_directory( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_create_directory::(thread, fd, path, path_len) + super::path_create_directory::(env, fd, path, path_len) } pub(crate) fn path_filestat_get( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, path_len: MemoryOffset, buf: WasmPtr<__wasi_filestat_t, MemoryType>, ) -> __wasi_errno_t { - super::path_filestat_get::(thread, fd, flags, path, path_len, buf) + super::path_filestat_get::(env, fd, flags, path, path_len, buf) } pub(crate) fn path_filestat_set_times( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, flags: __wasi_lookupflags_t, path: WasmPtr, @@ -264,12 +260,12 @@ pub(crate) fn path_filestat_set_times( fst_flags: __wasi_fstflags_t, ) -> __wasi_errno_t { super::path_filestat_set_times::( - thread, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, + env, fd, flags, path, path_len, st_atim, st_mtim, fst_flags, ) } pub(crate) fn path_link( - thread: &WasiThread, + env: &WasiEnv, old_fd: __wasi_fd_t, old_flags: __wasi_lookupflags_t, old_path: WasmPtr, @@ -279,7 +275,7 @@ pub(crate) fn path_link( new_path_len: MemoryOffset, ) -> __wasi_errno_t { super::path_link::( - thread, + env, old_fd, old_flags, old_path, @@ -291,7 +287,7 @@ pub(crate) fn path_link( } pub(crate) fn path_open( - thread: &WasiThread, + env: &WasiEnv, dirfd: __wasi_fd_t, dirflags: __wasi_lookupflags_t, path: WasmPtr, @@ -303,7 +299,7 @@ pub(crate) fn path_open( fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { super::path_open::( - thread, + env, dirfd, dirflags, path, @@ -317,7 +313,7 @@ pub(crate) fn path_open( } pub(crate) fn path_readlink( - thread: &WasiThread, + env: &WasiEnv, dir_fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, @@ -325,20 +321,20 @@ pub(crate) fn path_readlink( buf_len: MemoryOffset, buf_used: WasmPtr, ) -> __wasi_errno_t { - super::path_readlink::(thread, dir_fd, path, path_len, buf, buf_len, buf_used) + super::path_readlink::(env, dir_fd, path, path_len, buf, buf_len, buf_used) } pub(crate) fn path_remove_directory( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_remove_directory::(thread, fd, path, path_len) + super::path_remove_directory::(env, fd, path, path_len) } pub(crate) fn path_rename( - thread: &WasiThread, + env: &WasiEnv, old_fd: __wasi_fd_t, old_path: WasmPtr, old_path_len: MemoryOffset, @@ -347,7 +343,7 @@ pub(crate) fn path_rename( new_path_len: MemoryOffset, ) -> __wasi_errno_t { super::path_rename::( - thread, + env, old_fd, old_path, old_path_len, @@ -358,162 +354,159 @@ pub(crate) fn path_rename( } pub(crate) fn path_symlink( - thread: &WasiThread, + env: &WasiEnv, old_path: WasmPtr, old_path_len: MemoryOffset, fd: __wasi_fd_t, new_path: WasmPtr, new_path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_symlink::(thread, old_path, old_path_len, fd, new_path, new_path_len) + super::path_symlink::(env, old_path, old_path_len, fd, new_path, new_path_len) } pub(crate) fn path_unlink_file( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::path_unlink_file::(thread, fd, path, path_len) + super::path_unlink_file::(env, fd, path, path_len) } pub(crate) fn poll_oneoff( - thread: &WasiThread, + env: &WasiEnv, in_: WasmPtr<__wasi_subscription_t, MemoryType>, out_: WasmPtr<__wasi_event_t, MemoryType>, nsubscriptions: MemoryOffset, nevents: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::poll_oneoff::(thread, in_, out_, nsubscriptions, nevents) + super::poll_oneoff::(env, in_, out_, nsubscriptions, nevents) } -pub(crate) fn proc_exit(thread: &WasiThread, code: __wasi_exitcode_t) -> Result<(), WasiError> { - super::proc_exit(thread, code) +pub(crate) fn proc_exit(env: &WasiEnv, code: __wasi_exitcode_t) -> Result<(), WasiError> { + super::proc_exit(env, code) } -pub(crate) fn proc_raise(thread: &WasiThread, sig: __wasi_signal_t) -> __wasi_errno_t { - super::proc_raise(thread, sig) +pub(crate) fn proc_raise(env: &WasiEnv, sig: __wasi_signal_t) -> __wasi_errno_t { + super::proc_raise(env, sig) } pub(crate) fn random_get( - thread: &WasiThread, + env: &WasiEnv, buf: WasmPtr, buf_len: MemoryOffset, ) -> __wasi_errno_t { - super::random_get::(thread, buf, buf_len) + super::random_get::(env, buf, buf_len) } pub(crate) fn fd_dup( - thread: &WasiThread, + env: &WasiEnv, fd: __wasi_fd_t, ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_dup::(thread, fd, ret_fd) + super::fd_dup::(env, fd, ret_fd) } pub(crate) fn fd_event( - thread: &WasiThread, + env: &WasiEnv, initial_val: u64, flags: __wasi_eventfdflags, ret_fd: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_event(thread, initial_val, flags, ret_fd) + super::fd_event(env, initial_val, flags, ret_fd) } pub(crate) fn fd_pipe( - thread: &WasiThread, + env: &WasiEnv, ro_fd1: WasmPtr<__wasi_fd_t, MemoryType>, ro_fd2: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::fd_pipe::(thread, ro_fd1, ro_fd2) + super::fd_pipe::(env, ro_fd1, ro_fd2) } pub(crate) fn tty_get( - thread: &WasiThread, + env: &WasiEnv, tty_state: WasmPtr<__wasi_tty_t, MemoryType>, ) -> __wasi_errno_t { - super::tty_get::(thread, tty_state) + super::tty_get::(env, tty_state) } pub(crate) fn tty_set( - thread: &WasiThread, + env: &WasiEnv, tty_state: WasmPtr<__wasi_tty_t, MemoryType>, ) -> __wasi_errno_t { - super::tty_set::(thread, tty_state) + super::tty_set::(env, tty_state) } pub(crate) fn getcwd( - thread: &WasiThread, + env: &WasiEnv, path: WasmPtr, path_len: WasmPtr, ) -> __wasi_errno_t { - super::getcwd::(thread, path, path_len) + super::getcwd::(env, path, path_len) } pub(crate) fn chdir( - thread: &WasiThread, + env: &WasiEnv, path: WasmPtr, path_len: MemoryOffset, ) -> __wasi_errno_t { - super::chdir::(thread, path, path_len) + super::chdir::(env, path, path_len) } pub(crate) fn thread_spawn( - thread: &WasiThread, + env: &WasiEnv, method: WasmPtr, method_len: MemoryOffset, user_data: u64, reactor: __wasi_bool_t, ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, ) -> __wasi_errno_t { - super::thread_spawn::(thread, method, method_len, user_data, reactor, ret_tid) + super::thread_spawn::(env, method, method_len, user_data, reactor, ret_tid) } pub(crate) fn thread_sleep( - thread: &WasiThread, + env: &WasiEnv, duration: __wasi_timestamp_t, ) -> Result<__wasi_errno_t, WasiError> { - super::thread_sleep(thread, duration) + super::thread_sleep(env, duration) } pub(crate) fn thread_id( - thread: &WasiThread, + env: &WasiEnv, ret_tid: WasmPtr<__wasi_tid_t, MemoryType>, ) -> __wasi_errno_t { - super::thread_id::(thread, ret_tid) + super::thread_id::(env, ret_tid) } -pub(crate) fn thread_join(thread: &WasiThread, tid: __wasi_tid_t) -> __wasi_errno_t { - super::thread_join(thread, tid) +pub(crate) fn thread_join(env: &WasiEnv, tid: __wasi_tid_t) -> Result<__wasi_errno_t, WasiError> { + super::thread_join(env, tid) } pub(crate) fn thread_parallelism( - thread: &WasiThread, + env: &WasiEnv, ret_parallelism: WasmPtr, ) -> __wasi_errno_t { - super::thread_parallelism::(thread, ret_parallelism) + super::thread_parallelism::(env, ret_parallelism) } pub(crate) fn thread_exit( - thread: &WasiThread, + env: &WasiEnv, exitcode: __wasi_exitcode_t, ) -> Result<__wasi_errno_t, WasiError> { - super::thread_exit(thread, exitcode) + super::thread_exit(env, exitcode) } -pub(crate) fn sched_yield(thread: &WasiThread) -> Result<__wasi_errno_t, WasiError> { - super::sched_yield(thread) +pub(crate) fn sched_yield(env: &WasiEnv) -> Result<__wasi_errno_t, WasiError> { + super::sched_yield(env) } -pub(crate) fn getpid( - thread: &WasiThread, - ret_pid: WasmPtr<__wasi_pid_t, MemoryType>, -) -> __wasi_errno_t { - super::getpid::(thread, ret_pid) +pub(crate) fn getpid(env: &WasiEnv, ret_pid: WasmPtr<__wasi_pid_t, MemoryType>) -> __wasi_errno_t { + super::getpid::(env, ret_pid) } -pub(crate) fn bus_spawn_local( - thread: &WasiThread, +pub(crate) fn process_spawn( + env: &WasiEnv, name: WasmPtr, name_len: MemoryOffset, chroot: __wasi_bool_t, @@ -527,9 +520,9 @@ pub(crate) fn bus_spawn_local( working_dir: WasmPtr, working_dir_len: MemoryOffset, ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, -) -> __wasi_errno_t { - super::bus_spawn_local::( - thread, +) -> __bus_errno_t { + super::process_spawn::( + env, name, name_len, chroot, @@ -546,56 +539,47 @@ pub(crate) fn bus_spawn_local( ) } -pub(crate) fn bus_spawn_remote( - thread: &WasiThread, +pub(crate) fn bus_open_local( + env: &WasiEnv, name: WasmPtr, name_len: MemoryOffset, - chroot: __wasi_bool_t, - args: WasmPtr, - args_len: MemoryOffset, - preopen: WasmPtr, - preopen_len: MemoryOffset, - working_dir: WasmPtr, - working_dir_len: MemoryOffset, - stdin: __wasi_stdiomode_t, - stdout: __wasi_stdiomode_t, - stderr: __wasi_stdiomode_t, + reuse: __wasi_bool_t, + ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, +) -> __bus_errno_t { + super::bus_open_local::(env, name, name_len, reuse, ret_bid) +} + +pub(crate) fn bus_open_remote( + env: &WasiEnv, + name: WasmPtr, + name_len: MemoryOffset, + reuse: __wasi_bool_t, instance: WasmPtr, instance_len: MemoryOffset, token: WasmPtr, token_len: MemoryOffset, - ret_handles: WasmPtr<__wasi_bus_handles_t, MemoryType>, -) -> __wasi_errno_t { - super::bus_spawn_remote::( - thread, + ret_bid: WasmPtr<__wasi_bid_t, MemoryType>, +) -> __bus_errno_t { + super::bus_open_remote::( + env, name, name_len, - chroot, - args, - args_len, - preopen, - preopen_len, - working_dir, - working_dir_len, - stdin, - stdout, - stderr, + reuse, instance, instance_len, token, token_len, - ret_handles, + ret_bid, ) } -pub(crate) fn bus_close(thread: &WasiThread, bid: __wasi_bid_t) -> __wasi_errno_t { - super::bus_close(thread, bid) +pub(crate) fn bus_close(env: &WasiEnv, bid: __wasi_bid_t) -> __bus_errno_t { + super::bus_close(env, bid) } -pub(crate) fn bus_invoke( - thread: &WasiThread, +pub(crate) fn bus_call( + env: &WasiEnv, bid: __wasi_bid_t, - cid: WasmPtr<__wasi_option_cid_t, MemoryType>, keep_alive: __wasi_bool_t, topic: WasmPtr, topic_len: MemoryOffset, @@ -603,180 +587,165 @@ pub(crate) fn bus_invoke( buf: WasmPtr, buf_len: MemoryOffset, ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, -) -> __wasi_errno_t { - super::bus_invoke::( - thread, bid, cid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, +) -> __bus_errno_t { + super::bus_call::( + env, bid, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, ) } -pub(crate) fn bus_fault( - thread: &WasiThread, - cid: __wasi_cid_t, - fault: __bus_errno_t, -) -> __wasi_errno_t { - super::bus_fault(thread, cid, fault) -} - -pub(crate) fn bus_drop(thread: &WasiThread, cid: __wasi_cid_t) -> __wasi_errno_t { - super::bus_drop(thread, cid) -} - -pub(crate) fn bus_reply( - thread: &WasiThread, - cid: __wasi_cid_t, - format: __wasi_busdataformat_t, - buf: WasmPtr, - buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::bus_reply::(thread, cid, format, buf, buf_len) -} - -pub(crate) fn bus_callback( - thread: &WasiThread, - cid: __wasi_cid_t, +pub(crate) fn bus_subcall( + env: &WasiEnv, + parent: __wasi_cid_t, + keep_alive: __wasi_bool_t, topic: WasmPtr, topic_len: MemoryOffset, format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: MemoryOffset, -) -> __wasi_errno_t { - super::bus_callback::(thread, cid, topic, topic_len, format, buf, buf_len) -} - -pub(crate) fn bus_listen( - thread: &WasiThread, - parent: WasmPtr<__wasi_option_cid_t, MemoryType>, - topic: WasmPtr, - topic_len: MemoryOffset, -) -> __wasi_errno_t { - super::bus_listen::(thread, parent, topic, topic_len) + ret_cid: WasmPtr<__wasi_cid_t, MemoryType>, +) -> __bus_errno_t { + super::bus_subcall::( + env, parent, keep_alive, topic, topic_len, format, buf, buf_len, ret_cid, + ) } pub(crate) fn bus_poll( - thread: &WasiThread, - bid: WasmPtr<__wasi_option_bid_t, MemoryType>, - timeout: WasmPtr<__wasi_timestamp_t, MemoryType>, + env: &WasiEnv, + timeout: __wasi_timestamp_t, events: WasmPtr, nevents: MemoryOffset, + malloc: WasmPtr, + malloc_len: MemoryOffset, ret_nevents: WasmPtr, -) -> __wasi_errno_t { - super::bus_poll::(thread, bid, timeout, events, nevents, ret_nevents) +) -> __bus_errno_t { + super::bus_poll::( + env, + timeout, + events, + nevents, + malloc, + malloc_len, + ret_nevents, + ) } -pub(crate) fn bus_poll_data( - thread: &WasiThread, - bid: WasmPtr<__wasi_option_bid_t, MemoryType>, - timeout: WasmPtr<__wasi_timestamp_t, MemoryType>, - topic: WasmPtr, - topic_len: MemoryOffset, +pub(crate) fn call_reply( + env: &WasiEnv, + cid: __wasi_cid_t, + format: __wasi_busdataformat_t, buf: WasmPtr, buf_len: MemoryOffset, - ret_evt: WasmPtr<__wasi_busevent_data_t, MemoryType>, -) -> __wasi_errno_t { - super::bus_poll_data::( - thread, bid, timeout, topic, topic_len, buf, buf_len, ret_evt, - ) +) -> __bus_errno_t { + super::call_reply::(env, cid, format, buf, buf_len) +} + +pub(crate) fn call_fault(env: &WasiEnv, cid: __wasi_cid_t, fault: __bus_errno_t) -> __bus_errno_t { + super::call_fault(env, cid, fault) +} + +pub(crate) fn call_close(env: &WasiEnv, cid: __wasi_cid_t) -> __bus_errno_t { + super::call_close(env, cid) } pub(crate) fn port_bridge( - thread: &WasiThread, + env: &WasiEnv, network: WasmPtr, network_len: MemoryOffset, token: WasmPtr, token_len: MemoryOffset, security: __wasi_streamsecurity_t, ) -> __wasi_errno_t { - super::port_bridge::(thread, network, network_len, token, token_len, security) + super::port_bridge::(env, network, network_len, token, token_len, security) } -pub(crate) fn port_unbridge(thread: &WasiThread) -> __wasi_errno_t { - super::port_unbridge(thread) +pub(crate) fn port_unbridge(env: &WasiEnv) -> __wasi_errno_t { + super::port_unbridge(env) } -pub(crate) fn port_dhcp_acquire(thread: &WasiThread) -> __wasi_errno_t { - super::port_dhcp_acquire(thread) +pub(crate) fn port_dhcp_acquire(env: &WasiEnv) -> __wasi_errno_t { + super::port_dhcp_acquire(env) } pub(crate) fn port_addr_add( - thread: &WasiThread, + env: &WasiEnv, addr: WasmPtr<__wasi_cidr_t, MemoryType>, ) -> __wasi_errno_t { - super::port_addr_add::(thread, addr) + super::port_addr_add::(env, addr) } pub(crate) fn port_addr_remove( - thread: &WasiThread, + env: &WasiEnv, addr: WasmPtr<__wasi_addr_t, MemoryType>, ) -> __wasi_errno_t { - super::port_addr_remove::(thread, addr) + super::port_addr_remove::(env, addr) } -pub(crate) fn port_addr_clear(thread: &WasiThread) -> __wasi_errno_t { - super::port_addr_clear(thread) +pub(crate) fn port_addr_clear(env: &WasiEnv) -> __wasi_errno_t { + super::port_addr_clear(env) } pub(crate) fn port_addr_list( - thread: &WasiThread, + env: &WasiEnv, addrs: WasmPtr<__wasi_cidr_t, MemoryType>, naddrs: WasmPtr, ) -> __wasi_errno_t { - super::port_addr_list::(thread, addrs, naddrs) + super::port_addr_list::(env, addrs, naddrs) } pub(crate) fn port_mac( - thread: &WasiThread, + env: &WasiEnv, ret_mac: WasmPtr<__wasi_hardwareaddress_t, MemoryType>, ) -> __wasi_errno_t { - super::port_mac::(thread, ret_mac) + super::port_mac::(env, ret_mac) } pub(crate) fn port_gateway_set( - thread: &WasiThread, + env: &WasiEnv, ip: WasmPtr<__wasi_addr_t, MemoryType>, ) -> __wasi_errno_t { - super::port_gateway_set::(thread, ip) + super::port_gateway_set::(env, ip) } pub(crate) fn port_route_add( - thread: &WasiThread, + env: &WasiEnv, cidr: WasmPtr<__wasi_cidr_t, MemoryType>, via_router: WasmPtr<__wasi_addr_t, MemoryType>, preferred_until: WasmPtr<__wasi_option_timestamp_t, MemoryType>, expires_at: WasmPtr<__wasi_option_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::port_route_add::(thread, cidr, via_router, preferred_until, expires_at) + super::port_route_add::(env, cidr, via_router, preferred_until, expires_at) } pub(crate) fn port_route_remove( - thread: &WasiThread, + env: &WasiEnv, ip: WasmPtr<__wasi_addr_t, MemoryType>, ) -> __wasi_errno_t { - super::port_route_remove::(thread, ip) + super::port_route_remove::(env, ip) } -pub(crate) fn port_route_clear(thread: &WasiThread) -> __wasi_errno_t { - super::port_route_clear(thread) +pub(crate) fn port_route_clear(env: &WasiEnv) -> __wasi_errno_t { + super::port_route_clear(env) } pub(crate) fn port_route_list( - thread: &WasiThread, + env: &WasiEnv, routes: WasmPtr<__wasi_route_t, MemoryType>, nroutes: WasmPtr, ) -> __wasi_errno_t { - super::port_route_list::(thread, routes, nroutes) + super::port_route_list::(env, routes, nroutes) } pub(crate) fn ws_connect( - thread: &WasiThread, + env: &WasiEnv, url: WasmPtr, url_len: MemoryOffset, ret_sock: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::ws_connect::(thread, url, url_len, ret_sock) + super::ws_connect::(env, url, url_len, ret_sock) } pub(crate) fn http_request( - thread: &WasiThread, + env: &WasiEnv, url: WasmPtr, url_len: MemoryOffset, method: WasmPtr, @@ -787,7 +756,7 @@ pub(crate) fn http_request( ret_handles: WasmPtr<__wasi_http_handles_t, MemoryType>, ) -> __wasi_errno_t { super::http_request::( - thread, + env, url, url_len, method, @@ -800,7 +769,7 @@ pub(crate) fn http_request( } pub(crate) fn http_status( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, status: WasmPtr<__wasi_http_status_t, MemoryType>, status_text: WasmPtr, @@ -808,169 +777,169 @@ pub(crate) fn http_status( headers: WasmPtr, headers_len: WasmPtr, ) -> __wasi_errno_t { - super::http_status::(thread, sock, status) + super::http_status::(env, sock, status) } pub(crate) fn sock_status( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ret_status: WasmPtr<__wasi_sockstatus_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_status::(thread, sock, ret_status) + super::sock_status::(env, sock, ret_status) } pub(crate) fn sock_addr_local( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ret_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_addr_local::(thread, sock, ret_addr) + super::sock_addr_local::(env, sock, ret_addr) } pub(crate) fn sock_addr_peer( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_addr_peer::(thread, sock, ro_addr) + super::sock_addr_peer::(env, sock, ro_addr) } pub(crate) fn sock_open( - thread: &WasiThread, + env: &WasiEnv, af: __wasi_addressfamily_t, ty: __wasi_socktype_t, pt: __wasi_sockproto_t, ro_sock: WasmPtr<__wasi_fd_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_open::(thread, af, ty, pt, ro_sock) + super::sock_open::(env, af, ty, pt, ro_sock) } pub(crate) fn sock_set_opt_flag( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, flag: __wasi_bool_t, ) -> __wasi_errno_t { - super::sock_set_opt_flag(thread, sock, opt, flag) + super::sock_set_opt_flag(env, sock, opt, flag) } pub(crate) fn sock_get_opt_flag( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_flag: WasmPtr<__wasi_bool_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_get_opt_flag::(thread, sock, opt, ret_flag) + super::sock_get_opt_flag::(env, sock, opt, ret_flag) } pub fn sock_set_opt_time( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_set_opt_time(thread, sock, opt, time) + super::sock_set_opt_time(env, sock, opt, time) } pub fn sock_get_opt_time( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_time: WasmPtr<__wasi_option_timestamp_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_get_opt_time(thread, sock, opt, ret_time) + super::sock_get_opt_time(env, sock, opt, ret_time) } pub fn sock_set_opt_size( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, size: __wasi_filesize_t, ) -> __wasi_errno_t { - super::sock_set_opt_size(thread, sock, opt, size) + super::sock_set_opt_size(env, sock, opt, size) } pub fn sock_get_opt_size( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, opt: __wasi_sockoption_t, ret_size: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_get_opt_size(thread, sock, opt, ret_size) + super::sock_get_opt_size(env, sock, opt, ret_size) } pub(crate) fn sock_join_multicast_v4( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_join_multicast_v4::(thread, sock, multiaddr, iface) + super::sock_join_multicast_v4::(env, sock, multiaddr, iface) } pub(crate) fn sock_leave_multicast_v4( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip4_t, MemoryType>, iface: WasmPtr<__wasi_addr_ip4_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_leave_multicast_v4::(thread, sock, multiaddr, iface) + super::sock_leave_multicast_v4::(env, sock, multiaddr, iface) } pub(crate) fn sock_join_multicast_v6( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, iface: u32, ) -> __wasi_errno_t { - super::sock_join_multicast_v6::(thread, sock, multiaddr, iface) + super::sock_join_multicast_v6::(env, sock, multiaddr, iface) } pub(crate) fn sock_leave_multicast_v6( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, multiaddr: WasmPtr<__wasi_addr_ip6_t, MemoryType>, iface: u32, ) -> __wasi_errno_t { - super::sock_leave_multicast_v6::(thread, sock, multiaddr, iface) + super::sock_leave_multicast_v6::(env, sock, multiaddr, iface) } pub(crate) fn sock_bind( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_bind::(thread, sock, addr) + super::sock_bind::(env, sock, addr) } pub(crate) fn sock_listen( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, backlog: MemoryOffset, ) -> __wasi_errno_t { - super::sock_listen::(thread, sock, backlog) + super::sock_listen::(env, sock, backlog) } pub(crate) fn sock_accept( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, fd_flags: __wasi_fdflags_t, ro_fd: WasmPtr<__wasi_fd_t, MemoryType>, ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_accept::(thread, sock, fd_flags, ro_fd, ro_addr) + super::sock_accept::(env, sock, fd_flags, ro_fd, ro_addr) } pub(crate) fn sock_connect( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> __wasi_errno_t { - super::sock_connect::(thread, sock, addr) + super::sock_connect::(env, sock, addr) } pub(crate) fn sock_recv( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, ri_data_len: MemoryOffset, @@ -979,7 +948,7 @@ pub(crate) fn sock_recv( ro_flags: WasmPtr<__wasi_roflags_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { super::sock_recv::( - thread, + env, sock, ri_data, ri_data_len, @@ -990,7 +959,7 @@ pub(crate) fn sock_recv( } pub(crate) fn sock_recv_from( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, ri_data: WasmPtr<__wasi_iovec_t, MemoryType>, ri_data_len: MemoryOffset, @@ -1000,7 +969,7 @@ pub(crate) fn sock_recv_from( ro_addr: WasmPtr<__wasi_addr_port_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { super::sock_recv_from::( - thread, + env, sock, ri_data, ri_data_len, @@ -1012,18 +981,18 @@ pub(crate) fn sock_recv_from( } pub(crate) fn sock_send( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, si_data_len: MemoryOffset, si_flags: __wasi_siflags_t, ret_data_len: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { - super::sock_send::(thread, sock, si_data, si_data_len, si_flags, ret_data_len) + super::sock_send::(env, sock, si_data, si_data_len, si_flags, ret_data_len) } pub(crate) fn sock_send_to( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, si_data: WasmPtr<__wasi_ciovec_t, MemoryType>, si_data_len: MemoryOffset, @@ -1032,7 +1001,7 @@ pub(crate) fn sock_send_to( ret_data_len: WasmPtr, ) -> Result<__wasi_errno_t, WasiError> { super::sock_send_to::( - thread, + env, sock, si_data, si_data_len, @@ -1043,26 +1012,26 @@ pub(crate) fn sock_send_to( } pub(crate) fn sock_send_file( - thread: &WasiThread, + env: &WasiEnv, out_fd: __wasi_fd_t, in_fd: __wasi_fd_t, offset: __wasi_filesize_t, count: __wasi_filesize_t, ret_sent: WasmPtr<__wasi_filesize_t, MemoryType>, ) -> Result<__wasi_errno_t, WasiError> { - unsafe { super::sock_send_file::(thread, out_fd, in_fd, offset, count, ret_sent) } + unsafe { super::sock_send_file::(env, out_fd, in_fd, offset, count, ret_sent) } } pub(crate) fn sock_shutdown( - thread: &WasiThread, + env: &WasiEnv, sock: __wasi_fd_t, how: __wasi_sdflags_t, ) -> __wasi_errno_t { - super::sock_shutdown(thread, sock, how) + super::sock_shutdown(env, sock, how) } pub(crate) fn resolve( - thread: &WasiThread, + env: &WasiEnv, host: WasmPtr, host_len: MemoryOffset, port: u16, @@ -1070,5 +1039,5 @@ pub(crate) fn resolve( nips: MemoryOffset, ret_nips: WasmPtr, ) -> __wasi_errno_t { - super::resolve::(thread, host, host_len, port, ips, nips, ret_nips) + super::resolve::(env, host, host_len, port, ips, nips, ret_nips) } diff --git a/lib/wasi/src/utils.rs b/lib/wasi/src/utils.rs index a0ce908b09d..77222889179 100644 --- a/lib/wasi/src/utils.rs +++ b/lib/wasi/src/utils.rs @@ -9,6 +9,18 @@ pub fn is_wasi_module(module: &Module) -> bool { get_wasi_version(module, false).is_some() } +#[allow(dead_code)] +/// Returns if the module is WASIX or not +pub fn is_wasix_module(module: &Module) -> bool { + match get_wasi_versions(module, false).ok_or(false) { + Ok(wasi_versions) => { + wasi_versions.contains(&WasiVersion::Wasix32v1) + || wasi_versions.contains(&WasiVersion::Wasix64v1) + } + Err(_) => false, + } +} + pub fn map_io_err(err: std::io::Error) -> __wasi_errno_t { use std::io::ErrorKind; match err.kind() { diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index fcbbf99e733..bb7c0e62cc7 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -1,7 +1,5 @@ use std::io::{Read, Write}; -#[cfg(feature = "js")] -use wasm_bindgen_test::*; use wasmer::{Instance, Module, Store}; use wasmer_wasi::{Pipe, WasiState}; @@ -24,6 +22,8 @@ mod sys { #[cfg(feature = "js")] mod js { + use wasm_bindgen_test::*; + #[wasm_bindgen_test] fn test_stdout() { super::test_stdout() @@ -74,15 +74,14 @@ fn test_stdout() { // Create the `WasiEnv`. let mut stdout = Pipe::default(); - let wasi_env = WasiState::new("command-name") + let mut wasi_env = WasiState::new("command-name") .args(&["Gordon"]) .stdout(Box::new(stdout.clone())) .finalize() .unwrap(); // Generate an `ImportObject`. - let mut wasi_thread = wasi_env.new_thread(); - let import_object = wasi_thread.import_object(&module).unwrap(); + let import_object = wasi_env.import_object(&module).unwrap(); // Let's instantiate the module with the imports. let instance = Instance::new(&module, &import_object).unwrap(); @@ -117,14 +116,13 @@ fn test_env() { .env("TEST", "VALUE") .env("TEST2", "VALUE2"); // panic!("envs: {:?}", wasi_state_builder.envs); - let wasi_env = wasi_state_builder + let mut wasi_env = wasi_state_builder .stdout(Box::new(stdout.clone())) .finalize() .unwrap(); // Generate an `ImportObject`. - let mut wasi_thread = wasi_env.new_thread(); - let import_object = wasi_thread.import_object(&module).unwrap(); + let import_object = wasi_env.import_object(&module).unwrap(); // Let's instantiate the module with the imports. let instance = Instance::new(&module, &import_object).unwrap(); @@ -145,7 +143,7 @@ fn test_stdin() { // Create the `WasiEnv`. let mut stdin = Pipe::new(); - let wasi_env = WasiState::new("command-name") + let mut wasi_env = WasiState::new("command-name") .stdin(Box::new(stdin.clone())) .finalize() .unwrap(); @@ -155,8 +153,7 @@ fn test_stdin() { stdin.write(&buf[..]).unwrap(); // Generate an `ImportObject`. - let mut wasi_thread = wasi_env.new_thread(); - let import_object = wasi_thread.import_object(&module).unwrap(); + let import_object = wasi_env.import_object(&module).unwrap(); // Let's instantiate the module with the imports. let instance = Instance::new(&module, &import_object).unwrap(); diff --git a/tests/integration/cli/tests/staticlib_engine_test_c_source.c b/tests/integration/cli/tests/staticlib_engine_test_c_source.c index 68a79f1a49d..0a3bc08878c 100644 --- a/tests/integration/cli/tests/staticlib_engine_test_c_source.c +++ b/tests/integration/cli/tests/staticlib_engine_test_c_source.c @@ -8,11 +8,13 @@ static void print_wasmer_error() { int error_len = wasmer_last_error_length(); - printf("Error len: `%d`\n", error_len); - char *error_str = (char *)malloc(error_len); - wasmer_last_error_message(error_str, error_len); - printf("Error str: `%s`\n", error_str); - free(error_str); + if (error_len > 0) { + printf("Error len: `%d`\n", error_len); + char *error_str = (char *)malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); + free(error_str); + } } int main() { diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 45b03921be0..7b9f0745369 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -7,7 +7,7 @@ use wasmer::{Imports, Instance, Module, Store}; use wasmer_vfs::{host_fs, mem_fs, FileSystem}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; use wasmer_wasi::{ - generate_import_object_from_thread, get_wasi_version, FsError, Pipe, VirtualFile, WasiEnv, + generate_import_object_from_env, get_wasi_version, FsError, Pipe, VirtualFile, WasiEnv, WasiState, WasiVersion, }; use wast::parser::{self, Parse, ParseBuffer, Parser}; @@ -90,7 +90,7 @@ impl<'a> WasiTest<'a> { if let Some(stdin) = &self.stdin { let state = env.state(); - let mut wasi_stdin = state.stdin().unwrap(); + let mut wasi_stdin = state.stdin().unwrap().unwrap(); // Then we can write to it! write!(wasi_stdin, "{}", stdin.stream)?; } @@ -227,9 +227,8 @@ impl<'a> WasiTest<'a> { /// Get the correct WASI import object for the given module and set it up with the /// [`WasiEnv`]. fn get_imports(&self, store: &Store, module: &Module, env: WasiEnv) -> anyhow::Result { - let thread = env.new_thread(); let version = self.get_version(module)?; - Ok(generate_import_object_from_thread(store, thread, version)) + Ok(generate_import_object_from_env(store, env, version)) } } From 0cd9dfe3e0f2654e2f5678afccd43dec131d7586 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 15 Jun 2022 11:29:02 +0200 Subject: [PATCH 9/9] Fixed linter warnings/errors --- benches/static_and_dynamic_functions.rs | 8 +- lib/api/src/sys/imports.rs | 2 +- lib/api/tests/sys_export.rs | 28 +++--- lib/api/tests/sys_externals.rs | 15 ++- lib/api/tests/sys_instance.rs | 2 +- lib/c-api/src/wasm_c_api/wasi/mod.rs | 29 +++--- lib/cache/benches/bench_filesystem_cache.rs | 4 +- lib/cli/src/commands/run/wasi.rs | 4 +- lib/middlewares/src/metering.rs | 4 +- lib/types/src/memory.rs | 2 + lib/vbus/src/lib.rs | 4 +- lib/vfs/src/lib.rs | 15 +-- lib/wasi-local-networking/src/lib.rs | 15 ++- lib/wasi/src/lib.rs | 24 ++--- lib/wasi/src/runtime.rs | 14 +-- lib/wasi/src/state/guard.rs | 53 +++++----- lib/wasi/src/state/mod.rs | 60 +++++------- lib/wasi/src/state/pipe.rs | 2 +- lib/wasi/src/state/socket.rs | 102 ++++++++++---------- lib/wasi/src/state/types.rs | 2 +- lib/wasi/src/syscalls/legacy/snapshot0.rs | 2 +- lib/wasi/src/syscalls/mod.rs | 55 +++++------ lib/wasi/tests/stdio.rs | 6 +- tests/compilers/imports.rs | 8 +- tests/compilers/issues.rs | 7 +- tests/compilers/metering.rs | 2 +- tests/integration/cli/tests/compile.rs | 2 +- tests/integration/cli/tests/create_exe.rs | 4 +- tests/lib/wast/src/wasi_wast.rs | 3 +- 29 files changed, 219 insertions(+), 259 deletions(-) diff --git a/benches/static_and_dynamic_functions.rs b/benches/static_and_dynamic_functions.rs index c809140dd52..f798d9a3e57 100644 --- a/benches/static_and_dynamic_functions.rs +++ b/benches/static_and_dynamic_functions.rs @@ -32,10 +32,10 @@ static BASIC_WAT: &str = r#"(module )"#; pub fn run_basic_static_function(store: &Store, compiler_name: &str, c: &mut Criterion) { - let module = Module::new(&store, BASIC_WAT).unwrap(); + let module = Module::new(store, BASIC_WAT).unwrap(); let import_object = imports! { "env" => { - "multiply" => Function::new_native(&store, |a: i32, b: i32| a * b), + "multiply" => Function::new_native(store, |a: i32, b: i32| a * b), }, }; let instance = Instance::new(&module, &import_object).unwrap(); @@ -93,10 +93,10 @@ pub fn run_basic_static_function(store: &Store, compiler_name: &str, c: &mut Cri } pub fn run_basic_dynamic_function(store: &Store, compiler_name: &str, c: &mut Criterion) { - let module = Module::new(&store, BASIC_WAT).unwrap(); + let module = Module::new(store, BASIC_WAT).unwrap(); let import_object = imports! { "env" => { - "multiply" => Function::new_native(&store, |a: i32, b: i32| a * b), + "multiply" => Function::new_native(store, |a: i32, b: i32| a * b), }, }; let instance = Instance::new(&module, &import_object).unwrap(); diff --git a/lib/api/src/sys/imports.rs b/lib/api/src/sys/imports.rs index 405b3985bfe..b1126836fcb 100644 --- a/lib/api/src/sys/imports.rs +++ b/lib/api/src/sys/imports.rs @@ -361,7 +361,7 @@ mod test { "small" => g.clone() }, "cat" => { - "small" => g.clone() + "small" => g } }; diff --git a/lib/api/tests/sys_export.rs b/lib/api/tests/sys_export.rs index 85473da296b..aed5c51f0b8 100644 --- a/lib/api/tests/sys_export.rs +++ b/lib/api/tests/sys_export.rs @@ -114,10 +114,10 @@ mod sys { let host_fn = |env: &MemEnv| { let mem = env.memory_ref().unwrap(); - assert_eq!(is_memory_instance_ref_strong(&mem), Some(false)); + assert_eq!(is_memory_instance_ref_strong(mem), Some(false)); let mem_clone = mem.clone(); assert_eq!(is_memory_instance_ref_strong(&mem_clone), Some(true)); - assert_eq!(is_memory_instance_ref_strong(&mem), Some(false)); + assert_eq!(is_memory_instance_ref_strong(mem), Some(false)); }; let f: TypedFunction<(), ()> = { @@ -136,7 +136,7 @@ mod sys { { let mem = instance.exports.get_memory("memory")?; - assert_eq!(is_memory_instance_ref_strong(&mem), Some(true)); + assert_eq!(is_memory_instance_ref_strong(mem), Some(true)); } let f: TypedFunction<(), ()> = instance.exports.get_native_function("call_host_fn")?; @@ -158,10 +158,10 @@ mod sys { let host_fn = |env: &GlobalEnv| { let global = env.global_ref().unwrap(); - assert_eq!(is_global_instance_ref_strong(&global), Some(false)); + assert_eq!(is_global_instance_ref_strong(global), Some(false)); let global_clone = global.clone(); assert_eq!(is_global_instance_ref_strong(&global_clone), Some(true)); - assert_eq!(is_global_instance_ref_strong(&global), Some(false)); + assert_eq!(is_global_instance_ref_strong(global), Some(false)); }; let f: TypedFunction<(), ()> = { @@ -180,7 +180,7 @@ mod sys { { let global = instance.exports.get_global("global")?; - assert_eq!(is_global_instance_ref_strong(&global), Some(true)); + assert_eq!(is_global_instance_ref_strong(global), Some(true)); } let f: TypedFunction<(), ()> = instance.exports.get_native_function("call_host_fn")?; @@ -202,10 +202,10 @@ mod sys { let host_fn = |env: &TableEnv| { let table = env.table_ref().unwrap(); - assert_eq!(is_table_instance_ref_strong(&table), Some(false)); + assert_eq!(is_table_instance_ref_strong(table), Some(false)); let table_clone = table.clone(); assert_eq!(is_table_instance_ref_strong(&table_clone), Some(true)); - assert_eq!(is_table_instance_ref_strong(&table), Some(false)); + assert_eq!(is_table_instance_ref_strong(table), Some(false)); }; let f: TypedFunction<(), ()> = { @@ -224,7 +224,7 @@ mod sys { { let table = instance.exports.get_table("table")?; - assert_eq!(is_table_instance_ref_strong(&table), Some(true)); + assert_eq!(is_table_instance_ref_strong(table), Some(true)); } let f: TypedFunction<(), ()> = instance.exports.get_native_function("call_host_fn")?; @@ -246,10 +246,10 @@ mod sys { let host_fn = |env: &FunctionEnv| { let function = env.call_host_fn_ref().unwrap(); - assert_eq!(is_function_instance_ref_strong(&function), Some(false)); + assert_eq!(is_function_instance_ref_strong(function), Some(false)); let function_clone = function.clone(); assert_eq!(is_function_instance_ref_strong(&function_clone), Some(true)); - assert_eq!(is_function_instance_ref_strong(&function), Some(false)); + assert_eq!(is_function_instance_ref_strong(function), Some(false)); }; let f: TypedFunction<(), ()> = { @@ -268,7 +268,7 @@ mod sys { { let function = instance.exports.get_function("call_host_fn")?; - assert_eq!(is_function_instance_ref_strong(&function), Some(true)); + assert_eq!(is_function_instance_ref_strong(function), Some(true)); } let f: TypedFunction<(), ()> = instance.exports.get_native_function("call_host_fn")?; @@ -291,7 +291,7 @@ mod sys { let host_fn = |env: &FunctionEnv| { let function = env.call_host_fn_ref().unwrap(); assert_eq!( - is_native_function_instance_ref_strong(&function), + is_native_function_instance_ref_strong(function), Some(false) ); let function_clone = function.clone(); @@ -300,7 +300,7 @@ mod sys { Some(true) ); assert_eq!( - is_native_function_instance_ref_strong(&function), + is_native_function_instance_ref_strong(function), Some(false) ); }; diff --git a/lib/api/tests/sys_externals.rs b/lib/api/tests/sys_externals.rs index 8c4b865ddeb..baad342f8cf 100644 --- a/lib/api/tests/sys_externals.rs +++ b/lib/api/tests/sys_externals.rs @@ -94,7 +94,7 @@ mod sys { maximum: Some(1), }; let f = Function::new_native(&store, |num: i32| num + 1); - let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?; + let table = Table::new(&store, table_type, Value::FuncRef(Some(f)))?; assert_eq!(*table.ty(), table_type); let _elem = table.get(0).unwrap(); // assert_eq!(elem.funcref().unwrap(), f); @@ -123,7 +123,7 @@ mod sys { assert!(old_len.is_err()); // Growing to a bigger maximum should return None - let old_len = table.grow(5, Value::FuncRef(Some(f.clone())))?; + let old_len = table.grow(5, Value::FuncRef(Some(f)))?; assert_eq!(old_len, 0); Ok(()) @@ -238,11 +238,10 @@ mod sys { function.ty().clone(), FunctionType::new(vec![], vec![Type::I32]) ); - let function = Function::new_native_with_env( - &store, - my_env.clone(), - |_env: &MyEnv| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) }, - ); + let function = + Function::new_native_with_env(&store, my_env, |_env: &MyEnv| -> (i32, i64, f32, f64) { + (1, 2, 3.0, 4.0) + }); assert_eq!( function.ty().clone(), FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]) @@ -338,7 +337,7 @@ mod sys { let function = Function::new_with_env( &store, function_type, - my_env.clone(), + my_env, |_env: &MyEnv, _values: &[Value]| unimplemented!(), ); assert_eq!(function.ty().params(), [Type::V128]); diff --git a/lib/api/tests/sys_instance.rs b/lib/api/tests/sys_instance.rs index c1793cccf43..a89c5e6ceaf 100644 --- a/lib/api/tests/sys_instance.rs +++ b/lib/api/tests/sys_instance.rs @@ -50,7 +50,7 @@ mod sys { fn imported_fn(env: &Env, args: &[Val]) -> Result, RuntimeError> { let value = env.multiplier * args[0].unwrap_i32() as u32; - return Ok(vec![Val::I32(value as _)]); + Ok(vec![Val::I32(value as _)]) } let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]); diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 8c5244a9c9f..a285c916c02 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -16,8 +16,8 @@ use std::os::raw::c_char; use std::slice; use wasmer_api::{Exportable, Extern}; use wasmer_wasi::{ - generate_import_object_from_env, get_wasi_version, WasiEnv, WasiFile, WasiState, - WasiStateBuilder, WasiVersion, Pipe, + generate_import_object_from_env, get_wasi_version, Pipe, WasiEnv, WasiFile, WasiState, + WasiStateBuilder, WasiVersion, }; #[derive(Debug)] @@ -172,15 +172,11 @@ pub struct wasi_env_t { #[no_mangle] pub extern "C" fn wasi_env_new(mut config: Box) -> Option> { if !config.inherit_stdout { - config - .state_builder - .stdout(Box::new(Pipe::new())); + config.state_builder.stdout(Box::new(Pipe::new())); } if !config.inherit_stderr { - config - .state_builder - .stderr(Box::new(Pipe::new())); + config.state_builder.stderr(Box::new(Pipe::new())); } // TODO: impl capturer for stdin @@ -210,11 +206,11 @@ pub unsafe extern "C" fn wasi_env_read_stdout( read_inner(stdout, inner_buffer) } else { update_last_error("could not find a file handle for `stdout`"); - return -1; + -1 } } else { update_last_error("could not find a file handle for `stdout`"); - return -1; + -1 } } @@ -231,20 +227,23 @@ pub unsafe extern "C" fn wasi_env_read_stderr( read_inner(stderr, inner_buffer) } else { update_last_error("could not find a file handle for `stderr`"); - return -1; + -1 } } else { update_last_error("could not find a file handle for `stderr`"); - return -1; - } + -1 + } } -fn read_inner(wasi_file: &mut Box, inner_buffer: &mut [u8]) -> isize { +fn read_inner( + wasi_file: &mut Box, + inner_buffer: &mut [u8], +) -> isize { match wasi_file.read(inner_buffer) { Ok(a) => a as isize, Err(err) => { update_last_error(format!("failed to read wasi_file: {}", err)); - -1 + -1 } } } diff --git a/lib/cache/benches/bench_filesystem_cache.rs b/lib/cache/benches/bench_filesystem_cache.rs index efd942c96a4..b7b6a712b42 100644 --- a/lib/cache/benches/bench_filesystem_cache.rs +++ b/lib/cache/benches/bench_filesystem_cache.rs @@ -47,7 +47,7 @@ pub fn load_cache_universal(c: &mut Criterion) { fs_cache.store(key, &module).unwrap(); c.bench_function("load universal module in filesystem cache", |b| { - b.iter(|| unsafe { fs_cache.load(&store, key.clone()).unwrap() }) + b.iter(|| unsafe { fs_cache.load(&store, key).unwrap() }) }); } @@ -84,7 +84,7 @@ pub fn load_cache_native(c: &mut Criterion) { fs_cache.store(key, &module).unwrap(); c.bench_function("load native module in filesystem cache", |b| { - b.iter(|| unsafe { fs_cache.load(&store, key.clone()).unwrap() }) + b.iter(|| unsafe { fs_cache.load(&store, key).unwrap() }) }); } diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 3e987366b8f..f7e19820791 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -98,12 +98,12 @@ impl Wasi { let mut wasi_env = wasi_state_builder.finalize()?; wasi_env.state.fs.is_wasix.store( - is_wasix_module(&module), + is_wasix_module(module), std::sync::atomic::Ordering::Release, ); let import_object = wasi_env.import_object_for_all_wasi_versions(module)?; - let instance = Instance::new(&module, &import_object)?; + let instance = Instance::new(module, &import_object)?; Ok(instance) } diff --git a/lib/middlewares/src/metering.rs b/lib/middlewares/src/metering.rs index a8faf51c817..6ae7e6a639e 100644 --- a/lib/middlewares/src/metering.rs +++ b/lib/middlewares/src/metering.rs @@ -382,7 +382,7 @@ mod tests { fn get_remaining_points_works() { let metering = Arc::new(Metering::new(10, cost_function)); let mut compiler_config = Cranelift::default(); - compiler_config.push_middleware(metering.clone()); + compiler_config.push_middleware(metering); let store = Store::new(&Universal::new(compiler_config).engine()); let module = Module::new(&store, bytecode()).unwrap(); @@ -427,7 +427,7 @@ mod tests { fn set_remaining_points_works() { let metering = Arc::new(Metering::new(10, cost_function)); let mut compiler_config = Cranelift::default(); - compiler_config.push_middleware(metering.clone()); + compiler_config.push_middleware(metering); let store = Store::new(&Universal::new(compiler_config).engine()); let module = Module::new(&store, bytecode()).unwrap(); diff --git a/lib/types/src/memory.rs b/lib/types/src/memory.rs index 5dae2b53c42..b49fb71a398 100644 --- a/lib/types/src/memory.rs +++ b/lib/types/src/memory.rs @@ -50,6 +50,8 @@ impl MemoryStyle { /// Trait for the `Memory32` and `Memory64` marker types. /// /// This allows code to be generic over 32-bit and 64-bit memories. +/// # Safety +/// Direct memory access is unsafe pub unsafe trait MemorySize: Copy { /// Type used to represent an offset into a memory. This is `u32` or `u64`. type Offset: Default diff --git a/lib/vbus/src/lib.rs b/lib/vbus/src/lib.rs index 0852a3e57be..e51ec11ffac 100644 --- a/lib/vbus/src/lib.rs +++ b/lib/vbus/src/lib.rs @@ -85,11 +85,11 @@ impl SpawnOptionsConfig { } pub fn remote_instance(&self) -> Option<&str> { - self.remote_instance.as_ref().map(|a| a.as_str()) + self.remote_instance.as_deref() } pub fn access_token(&self) -> Option<&str> { - self.access_token.as_ref().map(|a| a.as_str()) + self.access_token.as_deref() } } diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index 65e725215df..982b944b3ee 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -28,9 +28,9 @@ impl From for FileDescriptor { } } -impl Into for FileDescriptor { - fn into(self) -> u32 { - self.0 as u32 +impl From for u32 { + fn from(a: FileDescriptor) -> u32 { + a.0 as u32 } } @@ -162,7 +162,10 @@ impl OpenOptions { self } - pub fn open>(&mut self, path: P) -> Result> { + pub fn open>( + &mut self, + path: P, + ) -> Result> { self.opener.open(path.as_ref(), &self.conf) } } @@ -198,8 +201,8 @@ pub trait VirtualFile: fmt::Debug + Write + Read + Seek + Upcastable { /// Returns the number of bytes available. This function must not block fn bytes_available(&self) -> Result { - return Ok(self.bytes_available_read()?.unwrap_or(0usize) - + self.bytes_available_write()?.unwrap_or(0usize)); + Ok(self.bytes_available_read()?.unwrap_or(0usize) + + self.bytes_available_write()?.unwrap_or(0usize)) } /// Returns the number of bytes available. This function must not block diff --git a/lib/wasi-local-networking/src/lib.rs b/lib/wasi-local-networking/src/lib.rs index b6dc6924e7b..35bcb616f1e 100644 --- a/lib/wasi-local-networking/src/lib.rs +++ b/lib/wasi-local-networking/src/lib.rs @@ -174,7 +174,7 @@ pub struct LocalTcpListener { impl VirtualTcpListener for LocalTcpListener { fn accept(&self) -> Result<(Box, SocketAddr)> { if let Some(timeout) = &self.timeout { - return self.accept_timeout(timeout.clone()); + return self.accept_timeout(*timeout); } let (sock, addr) = self .stream @@ -183,7 +183,7 @@ impl VirtualTcpListener for LocalTcpListener { ( Box::new(LocalTcpStream { stream: sock, - addr: addr.clone(), + addr, connect_timeout: None, }), addr, @@ -231,7 +231,7 @@ impl VirtualTcpListener for LocalTcpListener { /// Gets the accept timeout fn timeout(&self) -> Result> { - Ok(self.timeout.clone()) + Ok(self.timeout) } fn addr_local(&self) -> Result { @@ -287,7 +287,7 @@ impl VirtualTcpSocket for LocalTcpStream { match ty { TimeType::ReadTimeout => self.stream.read_timeout().map_err(io_err_into_net_error), TimeType::WriteTimeout => self.stream.write_timeout().map_err(io_err_into_net_error), - TimeType::ConnectTimeout => Ok(self.connect_timeout.clone()), + TimeType::ConnectTimeout => Ok(self.connect_timeout), #[cfg(feature = "wasix")] TimeType::Linger => self.stream.linger().map_err(io_err_into_net_error), _ => Err(NetworkError::InvalidInput), @@ -321,7 +321,7 @@ impl VirtualTcpSocket for LocalTcpStream { } fn addr_peer(&self) -> Result { - Ok(self.addr.clone()) + Ok(self.addr) } fn flush(&mut self) -> Result<()> { @@ -483,10 +483,7 @@ impl VirtualUdpSocket for LocalUdpSocket { } fn addr_peer(&self) -> Result> { - self.0 - .peer_addr() - .map(|a| Some(a)) - .map_err(io_err_into_net_error) + self.0.peer_addr().map(Some).map_err(io_err_into_net_error) } } diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 71375e7725a..8d60b8e7526 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -64,7 +64,7 @@ use std::ops::Deref; use thiserror::Error; use wasmer::{ imports, Function, Imports, LazyInit, Memory, Memory32, MemoryAccessError, MemorySize, Module, - Store, WasmerEnv, TypedFunction, + Store, TypedFunction, WasmerEnv, }; pub use runtime::{ @@ -92,9 +92,9 @@ impl From for WasiThreadId { Self(id) } } -impl Into for WasiThreadId { - fn into(self) -> u32 { - self.0 as u32 +impl From for u32 { + fn from(t: WasiThreadId) -> u32 { + t.0 as u32 } } @@ -107,9 +107,9 @@ impl From for WasiBusProcessId { Self(id) } } -impl Into for WasiBusProcessId { - fn into(self) -> u32 { - self.0 as u32 +impl From for u32 { + fn from(id: WasiBusProcessId) -> u32 { + id.0 as u32 } } @@ -190,7 +190,7 @@ impl WasiEnv { } /// Returns a copy of the current runtime implementation for this environment - pub fn runtime<'a>(&'a self) -> &'a (dyn WasiRuntimeImplementation) { + pub fn runtime(&self) -> &(dyn WasiRuntimeImplementation) { self.runtime.deref() } @@ -321,12 +321,12 @@ impl WasiEnv { } /// Accesses the virtual networking implementation - pub fn net<'a>(&'a self) -> &'a (dyn VirtualNetworking) { + pub fn net(&self) -> &(dyn VirtualNetworking) { self.runtime.networking() } /// Accesses the virtual bus implementation - pub fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { + pub fn bus(&self) -> &(dyn VirtualBus) { self.runtime.bus() } pub(crate) fn get_memory_and_wasi_state(&self, _mem_index: u32) -> (&Memory, &WasiState) { @@ -593,7 +593,7 @@ fn generate_import_object_wasix32_v1(store: &Store, env: WasiEnv) -> Imports { "sock_send_to" => Function::new_native_with_env(store, env.clone(), sock_send_to), "sock_send_file" => Function::new_native_with_env(store, env.clone(), sock_send_file), "sock_shutdown" => Function::new_native_with_env(store, env.clone(), sock_shutdown), - "resolve" => Function::new_native_with_env(store, env.clone(), resolve), + "resolve" => Function::new_native_with_env(store, env, resolve), } } } @@ -708,7 +708,7 @@ fn generate_import_object_wasix64_v1(store: &Store, env: WasiEnv) -> Imports { "sock_send_to" => Function::new_native_with_env(store, env.clone(), sock_send_to), "sock_send_file" => Function::new_native_with_env(store, env.clone(), sock_send_file), "sock_shutdown" => Function::new_native_with_env(store, env.clone(), sock_shutdown), - "resolve" => Function::new_native_with_env(store, env.clone(), resolve), + "resolve" => Function::new_native_with_env(store, env, resolve), } } } diff --git a/lib/wasi/src/runtime.rs b/lib/wasi/src/runtime.rs index e24f5c52f55..00c208bd166 100644 --- a/lib/wasi/src/runtime.rs +++ b/lib/wasi/src/runtime.rs @@ -17,9 +17,9 @@ pub enum WasiThreadError { MethodNotFound, } -impl Into<__wasi_errno_t> for WasiThreadError { - fn into(self) -> __wasi_errno_t { - match self { +impl From for __wasi_errno_t { + fn from(a: WasiThreadError) -> __wasi_errno_t { + match a { WasiThreadError::Unsupported => __WASI_ENOTSUP, WasiThreadError::MethodNotFound => __WASI_EINVAL, } @@ -46,11 +46,11 @@ pub trait WasiRuntimeImplementation: fmt::Debug + Sync { /// which allows runtimes to pass serialized messages between each other similar to /// RPC's. BUS implementation can be implemented that communicate across runtimes /// thus creating a distributed computing architecture. - fn bus<'a>(&'a self) -> &'a (dyn VirtualBus); + fn bus(&self) -> &(dyn VirtualBus); /// Provides access to all the networking related functions such as sockets. /// By default networking is not implemented. - fn networking<'a>(&'a self) -> &'a (dyn VirtualNetworking); + fn networking(&self) -> &(dyn VirtualNetworking); /// Generates a new thread ID fn thread_generate_id(&self) -> WasiThreadId; @@ -137,11 +137,11 @@ impl Default for PluggableRuntimeImplementation { } impl WasiRuntimeImplementation for PluggableRuntimeImplementation { - fn bus<'a>(&'a self) -> &'a (dyn VirtualBus) { + fn bus(&self) -> &(dyn VirtualBus) { self.bus.deref() } - fn networking<'a>(&'a self) -> &'a (dyn VirtualNetworking) { + fn networking(&self) -> &(dyn VirtualNetworking) { self.networking.deref() } diff --git a/lib/wasi/src/state/guard.rs b/lib/wasi/src/state/guard.rs index 8e21647de35..e37c9c97845 100644 --- a/lib/wasi/src/state/guard.rs +++ b/lib/wasi/src/state/guard.rs @@ -1,7 +1,8 @@ -use std::{sync::{ - RwLockReadGuard, RwLockWriteGuard -}, io::{Seek, Read}}; use super::*; +use std::{ + io::{Read, Seek}, + sync::{RwLockReadGuard, RwLockWriteGuard}, +}; #[derive(Debug)] pub(crate) struct InodeValFileReadGuard<'a> { @@ -48,34 +49,30 @@ pub(crate) struct WasiStateFileGuard { inode: generational_arena::Index, } -impl WasiStateFileGuard -{ +impl WasiStateFileGuard { pub fn new(state: &WasiState, fd: __wasi_fd_t) -> Result, FsError> { let inodes = state.inodes.read().unwrap(); let fd_map = state.fs.fd_map.read().unwrap(); if let Some(fd) = fd_map.get(&fd) { let guard = inodes.arena[fd.inode].read(); if let Kind::File { .. } = guard.deref() { - Ok( - Some( - Self { - inodes: state.inodes.clone(), - inode: fd.inode - } - ) - ) + Ok(Some(Self { + inodes: state.inodes.clone(), + inode: fd.inode, + })) } else { // Our public API should ensure that this is not possible Err(FsError::NotAFile) } - } else { Ok(None) } } - pub fn lock_read<'a>(&self, inodes: &'a RwLockReadGuard) -> InodeValFileReadGuard<'a> - { + pub fn lock_read<'a>( + &self, + inodes: &'a RwLockReadGuard, + ) -> InodeValFileReadGuard<'a> { let guard = inodes.arena[self.inode].read(); if let Kind::File { .. } = guard.deref() { InodeValFileReadGuard { guard } @@ -85,8 +82,10 @@ impl WasiStateFileGuard } } - pub fn lock_write<'a>(&self, inodes: &'a RwLockReadGuard) -> InodeValFileWriteGuard<'a> - { + pub fn lock_write<'a>( + &self, + inodes: &'a RwLockReadGuard, + ) -> InodeValFileWriteGuard<'a> { let guard = inodes.arena[self.inode].write(); if let Kind::File { .. } = guard.deref() { InodeValFileWriteGuard { guard } @@ -97,9 +96,7 @@ impl WasiStateFileGuard } } -impl VirtualFile -for WasiStateFileGuard -{ +impl VirtualFile for WasiStateFileGuard { fn last_accessed(&self) -> u64 { let inodes = self.inodes.read().unwrap(); let guard = self.lock_read(&inodes); @@ -221,9 +218,7 @@ for WasiStateFileGuard } } -impl Write -for WasiStateFileGuard -{ +impl Write for WasiStateFileGuard { fn write(&mut self, buf: &[u8]) -> std::io::Result { let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write(&inodes); @@ -255,9 +250,7 @@ for WasiStateFileGuard } } -impl Read -for WasiStateFileGuard -{ +impl Read for WasiStateFileGuard { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write(&inodes); @@ -279,9 +272,7 @@ for WasiStateFileGuard } } -impl Seek -for WasiStateFileGuard -{ +impl Seek for WasiStateFileGuard { fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { let inodes = self.inodes.read().unwrap(); let mut guard = self.lock_write(&inodes); @@ -291,4 +282,4 @@ for WasiStateFileGuard Err(std::io::ErrorKind::Unsupported.into()) } } -} \ No newline at end of file +} diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 484bc34c780..1f34a3f92fa 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -16,16 +16,16 @@ #![allow(clippy::cognitive_complexity, clippy::too_many_arguments)] mod builder; +mod guard; mod pipe; mod socket; mod types; -mod guard; pub use self::builder::*; +pub use self::guard::*; pub use self::pipe::*; pub use self::socket::*; pub use self::types::*; -pub use self::guard::*; use crate::syscalls::types::*; use crate::utils::map_io_err; use crate::WasiBusProcessId; @@ -1232,13 +1232,12 @@ impl WasiFs { path: &str, follow_symlinks: bool, ) -> Result { - let start_inode; - if path.starts_with("/") == false && self.is_wasix.load(Ordering::Acquire) { + let start_inode = if !path.starts_with('/') && self.is_wasix.load(Ordering::Acquire) { let (cur_inode, _) = self.get_current_dir(inodes, base)?; - start_inode = cur_inode; + cur_inode } else { - start_inode = self.get_fd_inode(base)?; - } + self.get_fd_inode(base)? + }; self.get_inode_at_path_inner(inodes, start_inode, path, 0, follow_symlinks) } @@ -1294,7 +1293,7 @@ impl WasiFs { fd: __wasi_fd_t, ) -> Result<__wasi_filestat_t, __wasi_errno_t> { let inode = self.get_fd_inode(fd)?; - Ok(inodes.arena[inode].stat.read().unwrap().deref().clone()) + Ok(*inodes.arena[inode].stat.read().unwrap().deref()) } pub fn fdstat( @@ -1390,7 +1389,7 @@ impl WasiFs { .stdout_mut(&self.fd_map) .map_err(fs_error_into_wasi_err)? .as_mut() - .and_then(|f| Some(f.flush().map_err(map_io_err))) + .map(|f| f.flush().map_err(map_io_err)) .unwrap_or_else(|| Err(__WASI_EIO))?, __WASI_STDERR_FILENO => inodes .stderr_mut(&self.fd_map) @@ -1406,13 +1405,9 @@ impl WasiFs { let mut guard = inodes.arena[fd.inode].write(); match guard.deref_mut() { - Kind::File { handle, .. } => { - if let Some(file) = handle { - file.flush().map_err(|_| __WASI_EIO)? - } else { - return Err(__WASI_EIO); - } - } + Kind::File { + handle: Some(file), .. + } => file.flush().map_err(|_| __WASI_EIO)?, // TODO: verify this behavior Kind::Dir { .. } => return Err(__WASI_EISDIR), Kind::Symlink { .. } => unimplemented!("WasiFs::flush Kind::Symlink"), @@ -1872,9 +1867,7 @@ impl WasiState { } /// Get the `VirtualFile` object at stdout - pub fn stdout( - &self, - ) -> Result>, FsError> { + pub fn stdout(&self) -> Result>, FsError> { self.std_dev_get(__WASI_STDOUT_FILENO) } @@ -1883,15 +1876,13 @@ impl WasiState { note = "stdout_mut() is no longer needed - just use stdout() instead" )] pub fn stdout_mut( - &self + &self, ) -> Result>, FsError> { self.stdout() } - + /// Get the `VirtualFile` object at stderr - pub fn stderr( - &self, - ) -> Result>, FsError> { + pub fn stderr(&self) -> Result>, FsError> { self.std_dev_get(__WASI_STDERR_FILENO) } @@ -1900,15 +1891,13 @@ impl WasiState { note = "stderr_mut() is no longer needed - just use stderr() instead" )] pub fn stderr_mut( - &self + &self, ) -> Result>, FsError> { self.stderr() } /// Get the `VirtualFile` object at stdin - pub fn stdin( - &self, - ) -> Result>, FsError> { + pub fn stdin(&self) -> Result>, FsError> { self.std_dev_get(__WASI_STDIN_FILENO) } @@ -1917,7 +1906,7 @@ impl WasiState { note = "stdin_mut() is no longer needed - just use stdin() instead" )] pub fn stdin_mut( - &self + &self, ) -> Result>, FsError> { self.stdin() } @@ -1928,15 +1917,12 @@ impl WasiState { &self, fd: __wasi_fd_t, ) -> Result>, FsError> { - let ret = WasiStateFileGuard::new(self, fd)? - .map(|a| { - let ret = Box::new(a); - let ret: Box = ret; - ret - }); - Ok( + let ret = WasiStateFileGuard::new(self, fd)?.map(|a| { + let ret = Box::new(a); + let ret: Box = ret; ret - ) + }); + Ok(ret) } } diff --git a/lib/wasi/src/state/pipe.rs b/lib/wasi/src/state/pipe.rs index b46133e7f09..b49e4040812 100644 --- a/lib/wasi/src/state/pipe.rs +++ b/lib/wasi/src/state/pipe.rs @@ -109,7 +109,7 @@ impl Read for WasiPipe { let data = rx.recv().map_err(|_| { io::Error::new( io::ErrorKind::BrokenPipe, - format!("the wasi pipe is not connected"), + "the wasi pipe is not connected".to_string(), ) })?; self.read_buffer.replace(Bytes::from(data)); diff --git a/lib/wasi/src/state/socket.rs b/lib/wasi/src/state/socket.rs index bd44a2c2a2b..290b154b766 100644 --- a/lib/wasi/src/state/socket.rs +++ b/lib/wasi/src/state/socket.rs @@ -120,7 +120,7 @@ impl From<__wasi_sockoption_t> for WasiSocketOption { __WASI_SOCK_OPTION_MULTICAST_TTL_V4 => MulticastTtlV4, __WASI_SOCK_OPTION_TYPE => Type, __WASI_SOCK_OPTION_PROTO => Proto, - _ => return Noop, + _ => Noop, } } } @@ -174,12 +174,12 @@ impl InodeSocket { } => { match *family { __WASI_ADDRESS_FAMILY_INET4 => { - if set_addr.is_ipv4() == false { + if !set_addr.is_ipv4() { return Err(__WASI_EINVAL); } } __WASI_ADDRESS_FAMILY_INET6 => { - if set_addr.is_ipv6() == false { + if !set_addr.is_ipv6() { return Err(__WASI_EINVAL); } } @@ -189,7 +189,7 @@ impl InodeSocket { } addr.replace(set_addr); - let addr = addr.clone().unwrap(); + let addr = (*addr).unwrap(); Ok(match *ty { __WASI_SOCK_TYPE_STREAM => { @@ -229,13 +229,13 @@ impl InodeSocket { if addr.is_none() { return Err(__WASI_EINVAL); } - let addr = addr.as_ref().unwrap().clone(); + let addr = *addr.as_ref().unwrap(); let mut socket = net .listen_tcp(addr, *only_v6, *reuse_port, *reuse_addr) .map_err(net_error_into_wasi_err)?; if let Some(accept_timeout) = accept_timeout { socket - .set_timeout(Some(accept_timeout.clone())) + .set_timeout(Some(*accept_timeout)) .map_err(net_error_into_wasi_err)?; } Some(InodeSocket::new(InodeSocketKind::TcpListener(socket))) @@ -292,7 +292,7 @@ impl InodeSocket { } => Ok(match *ty { __WASI_SOCK_TYPE_STREAM => { let addr = match addr { - Some(a) => a.clone(), + Some(a) => *a, None => { let ip = match peer.is_ipv4() { true => IpAddr::V4(Ipv4Addr::UNSPECIFIED), @@ -302,16 +302,16 @@ impl InodeSocket { } }; let mut socket = net - .connect_tcp(addr, peer, connect_timeout.clone()) + .connect_tcp(addr, peer, *connect_timeout) .map_err(net_error_into_wasi_err)?; if let Some(timeout) = send_timeout { socket - .set_opt_time(TimeType::WriteTimeout, Some(timeout.clone())) + .set_opt_time(TimeType::WriteTimeout, Some(*timeout)) .map_err(net_error_into_wasi_err)?; } if let Some(timeout) = recv_timeout { socket - .set_opt_time(TimeType::ReadTimeout, Some(timeout.clone())) + .set_opt_time(TimeType::ReadTimeout, Some(*timeout)) .map_err(net_error_into_wasi_err)?; } Some(InodeSocket::new(InodeSocketKind::TcpStream(socket))) @@ -366,12 +366,12 @@ impl InodeSocket { Ok(match &self.kind { InodeSocketKind::PreSocket { family, addr, .. } => { if let Some(addr) = addr { - addr.clone() + *addr } else { SocketAddr::new( - match family { - &__WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), - &__WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + match *family { + __WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + __WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), _ => return Err(__WASI_EINVAL), }, 0, @@ -396,9 +396,9 @@ impl InodeSocket { pub fn addr_peer(&self) -> Result { Ok(match &self.kind { InodeSocketKind::PreSocket { family, .. } => SocketAddr::new( - match family { - &__WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), - &__WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), + match *family { + __WASI_ADDRESS_FAMILY_INET4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED), + __WASI_ADDRESS_FAMILY_INET6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED), _ => return Err(__WASI_EINVAL), }, 0, @@ -409,7 +409,7 @@ impl InodeSocket { InodeSocketKind::UdpSocket(sock) => sock .addr_peer() .map_err(net_error_into_wasi_err)? - .map(|addr| Ok(addr)) + .map(Ok) .unwrap_or_else(|| { sock.addr_local() .map_err(net_error_into_wasi_err) @@ -533,7 +533,7 @@ impl InodeSocket { pub fn send_buf_size(&self) -> Result { match &self.kind { InodeSocketKind::PreSocket { send_buf_size, .. } => { - Ok(send_buf_size.clone().unwrap_or_default()) + Ok((*send_buf_size).unwrap_or_default()) } InodeSocketKind::TcpStream(sock) => { sock.send_buf_size().map_err(net_error_into_wasi_err) @@ -561,7 +561,7 @@ impl InodeSocket { pub fn recv_buf_size(&self) -> Result { match &self.kind { InodeSocketKind::PreSocket { recv_buf_size, .. } => { - Ok(recv_buf_size.clone().unwrap_or_default()) + Ok((*recv_buf_size).unwrap_or_default()) } InodeSocketKind::TcpStream(sock) => { sock.recv_buf_size().map_err(net_error_into_wasi_err) @@ -653,10 +653,10 @@ impl InodeSocket { accept_timeout, .. } => match ty { - TimeType::ConnectTimeout => Ok(connect_timeout.clone()), - TimeType::AcceptTimeout => Ok(accept_timeout.clone()), - TimeType::ReadTimeout => Ok(recv_timeout.clone()), - TimeType::WriteTimeout => Ok(send_timeout.clone()), + TimeType::ConnectTimeout => Ok(*connect_timeout), + TimeType::AcceptTimeout => Ok(*accept_timeout), + TimeType::ReadTimeout => Ok(*recv_timeout), + TimeType::WriteTimeout => Ok(*send_timeout), _ => Err(__WASI_EINVAL), }, InodeSocketKind::Closed => Err(__WASI_EIO), @@ -781,7 +781,7 @@ impl InodeSocket { write_bytes(&mut buf, memory, iov)?; match &mut self.kind { InodeSocketKind::HttpRequest(sock, ty) => { - let sock = sock.lock().unwrap(); + let sock = sock.get_mut().unwrap(); match ty { InodeHttpSocketType::Request => { if sock.request.is_none() { @@ -819,7 +819,7 @@ impl InodeSocket { let buf_len = buf.len(); match &mut self.kind { InodeSocketKind::HttpRequest(sock, ty) => { - let sock = sock.lock().unwrap(); + let sock = sock.get_mut().unwrap(); match ty { InodeHttpSocketType::Request => { if sock.request.is_none() { @@ -901,7 +901,7 @@ impl InodeSocket { } let data = match &mut self.kind { InodeSocketKind::HttpRequest(sock, ty) => { - let sock = sock.lock().unwrap(); + let sock = sock.get_mut().unwrap(); match ty { InodeHttpSocketType::Response => { if sock.response.is_none() { @@ -957,12 +957,11 @@ impl InodeSocket { ) -> Result { loop { if let Some(buf) = self.read_buffer.as_mut() { - if buf.len() > 0 { + if !buf.is_empty() { let reader = buf.as_ref(); let ret = read_bytes(reader, memory, iov)?; let peer = self .read_addr - .clone() .unwrap_or_else(|| SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)); write_ip_port(memory, addr, peer.ip(), peer.port())?; return Ok(ret); @@ -989,7 +988,7 @@ impl InodeSocket { sock.shutdown(how).map_err(net_error_into_wasi_err)?; } InodeSocketKind::HttpRequest(http, ..) => { - let mut http = http.lock().unwrap(); + let http = http.get_mut().unwrap(); match how { Shutdown::Read => { http.response.take(); @@ -1027,20 +1026,20 @@ impl Read for InodeSocket { } let data = match &mut self.kind { InodeSocketKind::HttpRequest(sock, ty) => { - let sock = sock.lock().unwrap(); + let sock = sock.get_mut().unwrap(); match ty { InodeHttpSocketType::Response => { if sock.response.is_none() { return Err(io::Error::new( io::ErrorKind::BrokenPipe, - format!("the socket is not connected"), + "the socket is not connected".to_string(), )); } let response = sock.response.as_ref().unwrap(); Bytes::from(response.recv().map_err(|_| { io::Error::new( io::ErrorKind::BrokenPipe, - format!("the wasi pipe is not connected"), + "the wasi pipe is not connected".to_string(), ) })?) } @@ -1048,14 +1047,14 @@ impl Read for InodeSocket { if sock.headers.is_none() { return Err(io::Error::new( io::ErrorKind::BrokenPipe, - format!("the socket is not connected"), + "the socket is not connected".to_string(), )); } let headers = sock.headers.as_ref().unwrap(); let headers = headers.recv().map_err(|_| { io::Error::new( io::ErrorKind::BrokenPipe, - format!("the wasi pipe is not connected"), + "the wasi pipe is not connected".to_string(), ) })?; let headers = format!("{}: {}", headers.0, headers.1); @@ -1064,7 +1063,7 @@ impl Read for InodeSocket { _ => { return Err(io::Error::new( io::ErrorKind::Unsupported, - format!("the socket is of an unsupported type"), + "the socket is of an unsupported type".to_string(), )); } } @@ -1088,19 +1087,19 @@ impl Read for InodeSocket { InodeSocketKind::PreSocket { .. } => { return Err(io::Error::new( io::ErrorKind::NotConnected, - format!("the socket is not connected"), + "the socket is not connected".to_string(), )) } InodeSocketKind::Closed => { return Err(io::Error::new( io::ErrorKind::BrokenPipe, - format!("the socket has been closed"), + "the socket has been closed".to_string(), )) } _ => { return Err(io::Error::new( io::ErrorKind::Unsupported, - format!("the socket type is not supported"), + "the socket type is not supported".to_string(), )) } }; @@ -1112,22 +1111,19 @@ impl Read for InodeSocket { impl Drop for InodeSocket { fn drop(&mut self) { - match &self.kind { - InodeSocketKind::HttpRequest(http, ty) => { - let mut guard = http.lock().unwrap(); - match ty { - InodeHttpSocketType::Request => { - guard.request.take(); - } - InodeHttpSocketType::Response => { - guard.response.take(); - } - InodeHttpSocketType::Headers => { - guard.headers.take(); - } + if let InodeSocketKind::HttpRequest(http, ty) = &self.kind { + let mut guard = http.lock().unwrap(); + match ty { + InodeHttpSocketType::Request => { + guard.request.take(); + } + InodeHttpSocketType::Response => { + guard.response.take(); + } + InodeHttpSocketType::Headers => { + guard.headers.take(); } } - _ => {} } } } diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 86954e9aeb1..7842f68bc5d 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -148,7 +148,7 @@ pub fn wasi_error_into_bus_err(bus_error: __bus_errno_t) -> BusError { __BUS_EINVOKE => InvokeFailed, __BUS_ECONSUMED => AlreadyConsumed, __BUS_EMEMVIOLATION => MemoryAccessViolation, - __BUS_EUNKNOWN | _ => UnknownError, + /*__BUS_EUNKNOWN |*/ _ => UnknownError, } } diff --git a/lib/wasi/src/syscalls/legacy/snapshot0.rs b/lib/wasi/src/syscalls/legacy/snapshot0.rs index 615e0bee4d2..bf15b211966 100644 --- a/lib/wasi/src/syscalls/legacy/snapshot0.rs +++ b/lib/wasi/src/syscalls/legacy/snapshot0.rs @@ -126,7 +126,7 @@ pub fn poll_oneoff( // we start by adjusting `in_` into a format that the new code can understand let memory = env.memory(); - let nsubscriptions_offset: u32 = nsubscriptions.into(); + let nsubscriptions_offset: u32 = nsubscriptions; let in_origs = wasi_try_mem_ok!(in_.slice(memory, nsubscriptions_offset)); let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec()); diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index d66bcc15368..54812ad292b 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -147,10 +147,8 @@ where let fd_entry = state.fs.get_fd(sock)?; let ret = { - if rights != 0 { - if !has_rights(fd_entry.rights, rights) { - return Err(__WASI_EACCES); - } + if rights != 0 && !has_rights(fd_entry.rights, rights) { + return Err(__WASI_EACCES); } let inode_idx = fd_entry.inode; @@ -181,10 +179,8 @@ where let fd_entry = state.fs.get_fd(sock)?; let ret = { - if rights != 0 { - if !has_rights(fd_entry.rights, rights) { - return Err(__WASI_EACCES); - } + if rights != 0 && !has_rights(fd_entry.rights, rights) { + return Err(__WASI_EACCES); } let inode_idx = fd_entry.inode; @@ -216,10 +212,8 @@ where let (_, state, inodes) = env.get_memory_and_wasi_state_and_inodes(0); let fd_entry = state.fs.get_fd(sock)?; - if rights != 0 { - if !has_rights(fd_entry.rights, rights) { - return Err(__WASI_EACCES); - } + if rights != 0 && !has_rights(fd_entry.rights, rights) { + return Err(__WASI_EACCES); } let inode_idx = fd_entry.inode; @@ -262,10 +256,10 @@ fn write_buffer_array( let data = wasi_try_mem!(new_ptr.slice(memory, wasi_try!(to_offset::(sub_buffer.len())))); wasi_try_mem!(data.write_slice(sub_buffer)); - wasi_try_mem!( - wasi_try_mem!(new_ptr.add_offset(wasi_try!(to_offset::(sub_buffer.len())))) - .write(memory, 0) - ); + wasi_try_mem!(wasi_try_mem!( + new_ptr.add_offset(wasi_try!(to_offset::(sub_buffer.len()))) + ) + .write(memory, 0)); current_buffer_offset += sub_buffer.len() + 1; } @@ -1259,7 +1253,7 @@ pub fn fd_readdir( // maintain consistent order via lexacographic sorting let fs_info = wasi_try!(wasi_try!(state.fs_read_dir(path)) .collect::, _>>() - .map_err(|e| fs_error_into_wasi_err(e))); + .map_err(fs_error_into_wasi_err)); let mut entry_vec = wasi_try!(fs_info .into_iter() .map(|entry| { @@ -1968,12 +1962,7 @@ pub fn path_filestat_get_internal( flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, )?; if inodes.arena[file_inode].is_preopened { - Ok(inodes.arena[file_inode] - .stat - .read() - .unwrap() - .deref() - .clone()) + Ok(*inodes.arena[file_inode].stat.read().unwrap().deref()) } else { let guard = inodes.arena[file_inode].read(); state.fs.get_stat_for_kind(inodes.deref(), guard.deref()) @@ -2650,7 +2639,7 @@ pub fn path_rename( out }; // if the above operation failed we have to revert the previous change and then fail - if let Err(e) = result.clone() { + if let Err(e) = result { let mut guard = inodes.arena[source_parent_inode].write(); if let Kind::Dir { entries, .. } = guard.deref_mut() { entries.insert(source_entry_name, source_entry); @@ -3502,11 +3491,11 @@ pub fn thread_join(env: &WasiEnv, tid: __wasi_tid_t) -> Result<__wasi_errno_t, W let tid: WasiThreadId = tid.into(); let other_thread = { let guard = env.state.threading.lock().unwrap(); - guard.threads.get(&tid).map(|a| a.clone()) + guard.threads.get(&tid).cloned() }; if let Some(other_thread) = other_thread { loop { - if other_thread.join(Duration::from_millis(5)) == true { + if other_thread.join(Duration::from_millis(5)) { break; } env.yield_now()?; @@ -3621,7 +3610,7 @@ pub fn process_spawn( __WASI_STDIO_MODE_PIPED => StdioMode::Piped, __WASI_STDIO_MODE_INHERIT => StdioMode::Inherit, __WASI_STDIO_MODE_LOG => StdioMode::Log, - __WASI_STDIO_MODE_NULL | _ => StdioMode::Null, + /*__WASI_STDIO_MODE_NULL |*/ _ => StdioMode::Null, }; let process = wasi_try_bus!(bus @@ -3662,7 +3651,7 @@ pub fn process_spawn( }; let handles = __wasi_bus_handles_t { - bid: bid, + bid, stdin, stdout, stderr, @@ -3757,7 +3746,7 @@ fn bus_open_local_internal( let guard = env.state.threading.lock().unwrap(); if let Some(bid) = guard.process_reuse.get(&name) { if guard.processes.contains_key(bid) { - wasi_try_mem_bus!(ret_bid.write(memory, bid.clone().into())); + wasi_try_mem_bus!(ret_bid.write(memory, (*bid).into())); return __BUS_ESUCCESS; } } @@ -4074,7 +4063,7 @@ pub fn http_request( request: None, response: None, headers: socket.headers, - status: socket.status.clone(), + status: socket.status, }; let (memory, state, mut inodes) = env.get_memory_and_wasi_state_and_inodes_mut(0); @@ -4158,7 +4147,7 @@ pub fn http_status( true => __WASI_BOOL_TRUE, false => __WASI_BOOL_FALSE, }, - size: wasi_try!(http_status.size.try_into().map_err(|_| __WASI_EOVERFLOW)), + size: wasi_try!(Ok(http_status.size)), status: http_status.status, }; @@ -4312,7 +4301,7 @@ pub fn port_addr_list( for n in 0..addrs.len() { let nip = ref_addrs.index(n as u64); - super::state::write_cidr(memory, nip.as_ptr::(), addrs.get(n).unwrap().clone()); + super::state::write_cidr(memory, nip.as_ptr::(), *addrs.get(n).unwrap()); } __WASI_ESUCCESS @@ -5411,7 +5400,7 @@ pub fn resolve( let mut idx = 0; for found_ip in found_ips.iter().take(naddrs) { - super::state::write_ip(memory, addrs.index(idx).as_ptr::(), found_ip.clone()); + super::state::write_ip(memory, addrs.index(idx).as_ptr::(), *found_ip); idx += 1; } diff --git a/lib/wasi/tests/stdio.rs b/lib/wasi/tests/stdio.rs index bb7c0e62cc7..45dcd57e4de 100644 --- a/lib/wasi/tests/stdio.rs +++ b/lib/wasi/tests/stdio.rs @@ -23,7 +23,7 @@ mod sys { #[cfg(feature = "js")] mod js { use wasm_bindgen_test::*; - + #[wasm_bindgen_test] fn test_stdout() { super::test_stdout() @@ -161,8 +161,8 @@ fn test_stdin() { // Let's call the `_start` function, which is our `main` function in Rust. let start = instance.exports.get_function("_start").unwrap(); let result = start.call(&[]); - assert!(result.is_err() == false); - + assert!(!result.is_err()); + // We assure stdin is now empty let mut buf = Vec::new(); stdin.read_to_end(&mut buf).unwrap(); diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index b94c22caeea..869e330c6c5 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -38,7 +38,7 @@ fn get_module(store: &Store) -> Result { (start $foo) "#; - let module = Module::new(&store, &wat)?; + let module = Module::new(store, &wat)?; Ok(module) } @@ -311,7 +311,7 @@ fn get_module2(store: &Store) -> Result { (call 0)) "#; - let module = Module::new(&store, &wat)?; + let module = Module::new(store, &wat)?; Ok(module) } @@ -334,7 +334,7 @@ fn dynamic_function_with_env_wasmer_env_init_works(config: crate::Config) -> Res &module, &imports! { "host" => { - "fn" => Function::new_with_env(&store, FunctionType::new(vec![], vec![]), env.clone(), |env, _values| { + "fn" => Function::new_with_env(&store, FunctionType::new(vec![], vec![]), env, |env, _values| { assert!(env.memory_ref().is_some()); Ok(vec![]) }), @@ -375,7 +375,7 @@ fn multi_use_host_fn_manages_memory_correctly(config: crate::Config) -> Result<( let imports = imports! { "host" => { - "fn" => Function::new_native_with_env(&store, env.clone(), host_fn), + "fn" => Function::new_native_with_env(&store, env, host_fn), }, }; let instance1 = Instance::new(&module, &imports)?; diff --git a/tests/compilers/issues.rs b/tests/compilers/issues.rs index eddd6d250f2..dcb63c6c207 100644 --- a/tests/compilers/issues.rs +++ b/tests/compilers/issues.rs @@ -67,7 +67,7 @@ fn issue_2329(mut config: crate::Config) -> Result<()> { "env" => { "__read_memory" => Function::new_native_with_env( &store, - env.clone(), + env, read_memory ), } @@ -210,10 +210,7 @@ fn call_with_static_data_pointers(mut config: crate::Config) -> Result<()> { "mango", Function::new_native_with_env(&store, env.clone(), mango), ); - exports.insert( - "gas", - Function::new_native_with_env(&store, env.clone(), gas), - ); + exports.insert("gas", Function::new_native_with_env(&store, env, gas)); let mut imports = Imports::new(); imports.register_namespace("env", exports); let instance = Instance::new(&module, &imports)?; diff --git a/tests/compilers/metering.rs b/tests/compilers/metering.rs index d9ee5e35cd2..6732aa4fb33 100644 --- a/tests/compilers/metering.rs +++ b/tests/compilers/metering.rs @@ -101,7 +101,7 @@ fn complex_loop(mut config: crate::Config) -> Result<()> { // } // return y; // } - static WAT: &'static str = r#" + static WAT: &str = r#" (module (type $t0 (func (param i32 i32) (result i32))) (type $t1 (func)) diff --git a/tests/integration/cli/tests/compile.rs b/tests/integration/cli/tests/compile.rs index 17d50d081a6..8cba88de268 100644 --- a/tests/integration/cli/tests/compile.rs +++ b/tests/integration/cli/tests/compile.rs @@ -126,7 +126,7 @@ fn staticlib_engine_works() -> anyhow::Result<()> { WasmerCompile { current_dir: operating_dir.clone(), - wasm_path: wasm_path, + wasm_path, wasm_object_path: wasm_object_path.clone(), header_output_path, compiler: Compiler::Cranelift, diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index d1c2952b433..abb213c58b6 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -81,7 +81,7 @@ fn create_exe_works() -> anyhow::Result<()> { WasmerCreateExe { current_dir: operating_dir.clone(), - wasm_path: wasm_path, + wasm_path, native_executable_path: executable_path.clone(), compiler: Compiler::Cranelift, ..Default::default() @@ -114,7 +114,7 @@ fn create_exe_works_with_file() -> anyhow::Result<()> { WasmerCreateExe { current_dir: operating_dir.clone(), - wasm_path: wasm_path, + wasm_path, native_executable_path: executable_path.clone(), compiler: Compiler::Cranelift, ..Default::default() diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 7b9f0745369..f4e3aff5306 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -81,7 +81,7 @@ impl<'a> WasiTest<'a> { wasm_module.read_to_end(&mut out)?; out }; - let module = Module::new(&store, &wasm_bytes)?; + let module = Module::new(store, &wasm_bytes)?; let (env, _tempdirs, stdout_rx, stderr_rx) = self.create_wasi_env(filesystem_kind)?; let imports = self.get_imports(store, &module, env.clone())?; let instance = Instance::new(&module, &imports)?; @@ -125,6 +125,7 @@ impl<'a> WasiTest<'a> { } /// Create the wasi env with the given metadata. + #[allow(clippy::type_complexity)] fn create_wasi_env( &self, filesystem_kind: WasiFileSystemKind,