Implement sock_accept
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>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
use crate::block_on_dummy_executor;
|
||||
#[cfg(windows)]
|
||||
use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
|
||||
#[cfg(not(windows))]
|
||||
use io_lifetimes::AsFd;
|
||||
#[cfg(windows)]
|
||||
use io_lifetimes::{AsHandle, BorrowedHandle};
|
||||
use std::any::Any;
|
||||
use std::io;
|
||||
use wasi_common::{
|
||||
@@ -21,6 +21,54 @@ impl File {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpListener(wasi_cap_std_sync::net::TcpListener);
|
||||
|
||||
impl TcpListener {
|
||||
pub(crate) fn from_inner(listener: wasi_cap_std_sync::net::TcpListener) -> Self {
|
||||
TcpListener(listener)
|
||||
}
|
||||
pub fn from_cap_std(listener: cap_std::net::TcpListener) -> Self {
|
||||
Self::from_inner(wasi_cap_std_sync::net::TcpListener::from_cap_std(listener))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpStream(wasi_cap_std_sync::net::TcpStream);
|
||||
|
||||
impl TcpStream {
|
||||
pub(crate) fn from_inner(stream: wasi_cap_std_sync::net::TcpStream) -> Self {
|
||||
TcpStream(stream)
|
||||
}
|
||||
pub fn from_cap_std(stream: cap_std::net::TcpStream) -> Self {
|
||||
Self::from_inner(wasi_cap_std_sync::net::TcpStream::from_cap_std(stream))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub struct UnixListener(wasi_cap_std_sync::net::UnixListener);
|
||||
|
||||
#[cfg(unix)]
|
||||
impl UnixListener {
|
||||
pub(crate) fn from_inner(listener: wasi_cap_std_sync::net::UnixListener) -> Self {
|
||||
UnixListener(listener)
|
||||
}
|
||||
pub fn from_cap_std(listener: cap_std::os::unix::net::UnixListener) -> Self {
|
||||
Self::from_inner(wasi_cap_std_sync::net::UnixListener::from_cap_std(listener))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub struct UnixStream(wasi_cap_std_sync::net::UnixStream);
|
||||
|
||||
#[cfg(unix)]
|
||||
impl UnixStream {
|
||||
fn from_inner(stream: wasi_cap_std_sync::net::UnixStream) -> Self {
|
||||
UnixStream(stream)
|
||||
}
|
||||
pub fn from_cap_std(stream: cap_std::os::unix::net::UnixStream) -> Self {
|
||||
Self::from_inner(wasi_cap_std_sync::net::UnixStream::from_cap_std(stream))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Stdin(wasi_cap_std_sync::stdio::Stdin);
|
||||
|
||||
pub fn stdin() -> Stdin {
|
||||
@@ -175,17 +223,28 @@ macro_rules! wasi_file_impl {
|
||||
use wasi_common::ErrorExt;
|
||||
Err(Error::badf())
|
||||
}
|
||||
|
||||
async fn sock_accept(&mut self, fdflags: FdFlags) -> Result<Box<dyn WasiFile>, Error> {
|
||||
block_on_dummy_executor(|| self.0.sock_accept(fdflags))
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
impl AsHandle for $ty {
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
self.0.as_handle()
|
||||
impl AsRawHandleOrSocket for $ty {
|
||||
#[inline]
|
||||
fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
|
||||
self.0.as_raw_handle_or_socket()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
wasi_file_impl!(File);
|
||||
wasi_file_impl!(TcpListener);
|
||||
wasi_file_impl!(TcpStream);
|
||||
#[cfg(unix)]
|
||||
wasi_file_impl!(UnixListener);
|
||||
#[cfg(unix)]
|
||||
wasi_file_impl!(UnixStream);
|
||||
wasi_file_impl!(Stdin);
|
||||
wasi_file_impl!(Stdout);
|
||||
wasi_file_impl!(Stderr);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
mod dir;
|
||||
mod file;
|
||||
pub mod net;
|
||||
pub mod sched;
|
||||
pub mod stdio;
|
||||
|
||||
@@ -12,6 +13,9 @@ 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;
|
||||
|
||||
@@ -91,6 +95,19 @@ impl WasiCtxBuilder {
|
||||
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
|
||||
}
|
||||
|
||||
6
crates/wasi-common/tokio/src/net.rs
Normal file
6
crates/wasi-common/tokio/src/net.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
pub use crate::file::TcpListener;
|
||||
pub use crate::file::TcpStream;
|
||||
#[cfg(unix)]
|
||||
pub use crate::file::UnixListener;
|
||||
#[cfg(unix)]
|
||||
pub use crate::file::UnixStream;
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::block_on_dummy_executor;
|
||||
use io_lifetimes::AsHandle;
|
||||
use std::os::windows::io::{AsRawHandle, RawHandle};
|
||||
use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
|
||||
use wasi_cap_std_sync::sched::windows::poll_oneoff_;
|
||||
use wasi_common::{file::WasiFile, sched::Poll, Error};
|
||||
|
||||
@@ -16,35 +15,43 @@ pub fn wasi_file_is_stdin(f: &dyn WasiFile) -> bool {
|
||||
f.as_any().is::<crate::stdio::Stdin>()
|
||||
}
|
||||
|
||||
fn wasi_file_raw_handle(f: &dyn WasiFile) -> Option<RawHandle> {
|
||||
fn wasi_file_raw_handle(f: &dyn WasiFile) -> Option<RawHandleOrSocket> {
|
||||
let a = f.as_any();
|
||||
if a.is::<crate::file::File>() {
|
||||
Some(
|
||||
a.downcast_ref::<crate::file::File>()
|
||||
.unwrap()
|
||||
.as_handle()
|
||||
.as_raw_handle(),
|
||||
.as_raw_handle_or_socket(),
|
||||
)
|
||||
} else if a.is::<crate::net::TcpListener>() {
|
||||
Some(
|
||||
a.downcast_ref::<crate::net::TcpListener>()
|
||||
.unwrap()
|
||||
.as_raw_handle_or_socket(),
|
||||
)
|
||||
} else if a.is::<crate::net::TcpStream>() {
|
||||
Some(
|
||||
a.downcast_ref::<crate::net::TcpStream>()
|
||||
.unwrap()
|
||||
.as_raw_handle_or_socket(),
|
||||
)
|
||||
} else if a.is::<crate::stdio::Stdin>() {
|
||||
Some(
|
||||
a.downcast_ref::<crate::stdio::Stdin>()
|
||||
.unwrap()
|
||||
.as_handle()
|
||||
.as_raw_handle(),
|
||||
.as_raw_handle_or_socket(),
|
||||
)
|
||||
} else if a.is::<crate::stdio::Stdout>() {
|
||||
Some(
|
||||
a.downcast_ref::<crate::stdio::Stdout>()
|
||||
.unwrap()
|
||||
.as_handle()
|
||||
.as_raw_handle(),
|
||||
.as_raw_handle_or_socket(),
|
||||
)
|
||||
} else if a.is::<crate::stdio::Stderr>() {
|
||||
Some(
|
||||
a.downcast_ref::<crate::stdio::Stderr>()
|
||||
.unwrap()
|
||||
.as_handle()
|
||||
.as_raw_handle(),
|
||||
.as_raw_handle_or_socket(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
|
||||
Reference in New Issue
Block a user