With the addition of `sock_accept()` in `wasi-0.11.0`, wasmtime can now
implement basic networking for pre-opened sockets.
For Windows `AsHandle` was replaced with `AsRawHandleOrSocket` to cope
with the duality of Handles and Sockets.
For Unix a `wasi_cap_std_sync::net::Socket` enum was created to handle
the {Tcp,Unix}{Listener,Stream} more efficiently in
`WasiCtxBuilder::preopened_socket()`.
The addition of that many `WasiFile` implementors was mainly necessary,
because of the difference in the `num_ready_bytes()` function.
A known issue is Windows now busy polling on sockets, because except
for `stdin`, nothing is querying the status of windows handles/sockets.
Another know issue on Windows, is that there is no crate providing
support for `fcntl(fd, F_GETFL, 0)` on a socket.
Signed-off-by: Harald Hoyer <harald@profian.com>
134 lines
3.9 KiB
Rust
134 lines
3.9 KiB
Rust
#![cfg_attr(io_lifetimes_use_std, feature(io_safety))]
|
|
|
|
mod dir;
|
|
mod file;
|
|
pub mod net;
|
|
pub mod sched;
|
|
pub mod stdio;
|
|
|
|
use std::future::Future;
|
|
use std::path::Path;
|
|
pub use wasi_cap_std_sync::{clocks_ctx, random_ctx};
|
|
use wasi_common::{Error, Table, WasiCtx, WasiFile};
|
|
|
|
pub use dir::Dir;
|
|
pub use file::File;
|
|
pub use net::*;
|
|
use wasi_cap_std_sync::net::Socket;
|
|
use wasi_common::file::FileCaps;
|
|
|
|
use crate::sched::sched_ctx;
|
|
|
|
pub struct WasiCtxBuilder(WasiCtx);
|
|
|
|
impl WasiCtxBuilder {
|
|
pub fn new() -> Self {
|
|
WasiCtxBuilder(WasiCtx::new(
|
|
random_ctx(),
|
|
clocks_ctx(),
|
|
sched_ctx(),
|
|
Table::new(),
|
|
))
|
|
}
|
|
pub fn env(mut self, var: &str, value: &str) -> Result<Self, wasi_common::StringArrayError> {
|
|
self.0.push_env(var, value)?;
|
|
Ok(self)
|
|
}
|
|
pub fn envs(mut self, env: &[(String, String)]) -> Result<Self, wasi_common::StringArrayError> {
|
|
for (k, v) in env {
|
|
self.0.push_env(k, v)?;
|
|
}
|
|
Ok(self)
|
|
}
|
|
pub fn inherit_env(mut self) -> Result<Self, wasi_common::StringArrayError> {
|
|
for (key, value) in std::env::vars() {
|
|
self.0.push_env(&key, &value)?;
|
|
}
|
|
Ok(self)
|
|
}
|
|
pub fn arg(mut self, arg: &str) -> Result<Self, wasi_common::StringArrayError> {
|
|
self.0.push_arg(arg)?;
|
|
Ok(self)
|
|
}
|
|
pub fn args(mut self, arg: &[String]) -> Result<Self, wasi_common::StringArrayError> {
|
|
for a in arg {
|
|
self.0.push_arg(&a)?;
|
|
}
|
|
Ok(self)
|
|
}
|
|
pub fn inherit_args(mut self) -> Result<Self, wasi_common::StringArrayError> {
|
|
for arg in std::env::args() {
|
|
self.0.push_arg(&arg)?;
|
|
}
|
|
Ok(self)
|
|
}
|
|
pub fn stdin(mut self, f: Box<dyn WasiFile>) -> Self {
|
|
self.0.set_stdin(f);
|
|
self
|
|
}
|
|
pub fn stdout(mut self, f: Box<dyn WasiFile>) -> Self {
|
|
self.0.set_stdout(f);
|
|
self
|
|
}
|
|
pub fn stderr(mut self, f: Box<dyn WasiFile>) -> Self {
|
|
self.0.set_stderr(f);
|
|
self
|
|
}
|
|
pub fn inherit_stdin(self) -> Self {
|
|
self.stdin(Box::new(crate::stdio::stdin()))
|
|
}
|
|
pub fn inherit_stdout(self) -> Self {
|
|
self.stdout(Box::new(crate::stdio::stdout()))
|
|
}
|
|
pub fn inherit_stderr(self) -> Self {
|
|
self.stderr(Box::new(crate::stdio::stderr()))
|
|
}
|
|
pub fn inherit_stdio(self) -> Self {
|
|
self.inherit_stdin().inherit_stdout().inherit_stderr()
|
|
}
|
|
pub fn preopened_dir(
|
|
mut self,
|
|
dir: cap_std::fs::Dir,
|
|
guest_path: impl AsRef<Path>,
|
|
) -> Result<Self, Error> {
|
|
let dir = Box::new(crate::dir::Dir::from_cap_std(dir));
|
|
self.0.push_preopened_dir(dir, guest_path)?;
|
|
Ok(self)
|
|
}
|
|
pub fn preopened_socket(mut self, fd: u32, socket: impl Into<Socket>) -> Result<Self, Error> {
|
|
let socket: Socket = socket.into();
|
|
let file: Box<dyn WasiFile> = socket.into();
|
|
|
|
let caps = FileCaps::FDSTAT_SET_FLAGS
|
|
| FileCaps::FILESTAT_GET
|
|
| FileCaps::READ
|
|
| FileCaps::POLL_READWRITE;
|
|
|
|
self.0.insert_file(fd, file, caps);
|
|
Ok(self)
|
|
}
|
|
|
|
pub fn build(self) -> WasiCtx {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
// Much of this crate is implemented in terms of `async` methods from the
|
|
// wasi-cap-std-sync crate. These methods may be async in signature, however,
|
|
// they are synchronous in implementation (always Poll::Ready on first poll)
|
|
// and perform blocking syscalls.
|
|
//
|
|
// This function takes this blocking code and executes it using a dummy executor
|
|
// to assert its immediate readiness. We tell tokio this is a blocking operation
|
|
// with the block_in_place function.
|
|
pub(crate) fn block_on_dummy_executor<'a, F, Fut, T>(f: F) -> Result<T, Error>
|
|
where
|
|
F: FnOnce() -> Fut + Send + 'a,
|
|
Fut: Future<Output = Result<T, Error>>,
|
|
T: Send + 'static,
|
|
{
|
|
tokio::task::block_in_place(move || {
|
|
wiggle::run_in_dummy_executor(f()).expect("wrapped operation should be synchronous")
|
|
})
|
|
}
|