Skip to content

Commit

Permalink
Add support for WasmEdge.
Browse files Browse the repository at this point in the history
Signed-off-by: Tricster <mediosrity@gmail.com>
  • Loading branch information
MediosZ committed Jun 25, 2022
1 parent bcb6dd7 commit b73a96c
Show file tree
Hide file tree
Showing 10 changed files with 869 additions and 394 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ include = [
# For documentation of features see the `mio::features` module.
[features]
# By default Mio only provides a shell implementation.
default = []
default = ["wasmedge", "os-poll", "net"]

# Enables the `Poll` and `Registry` types.
os-poll = []
Expand All @@ -42,6 +42,8 @@ os-ext = [
# Enables `mio::net` module containing networking primitives.
net = []

wasmedge = []

[dependencies]
log = "0.4.8"

Expand All @@ -61,6 +63,7 @@ features = [
[target.'cfg(target_os = "wasi")'.dependencies]
wasi = "0.11.0"
libc = "0.2.121"
wasmedge_wasi_socket = {path = "../wasmedge_wasi_socket"}

[dev-dependencies]
env_logger = { version = "0.8.4", default-features = false }
Expand Down
4 changes: 2 additions & 2 deletions examples/tcp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const SERVER: Token = Token(0);
// Some data we'll send over the connection.
const DATA: &[u8] = b"Hello world!\n";

#[cfg(not(target_os = "wasi"))]
#[cfg(any(not(target_os = "wasi"), feature = "wasmedge"))]
fn main() -> io::Result<()> {
env_logger::init();

Expand Down Expand Up @@ -183,7 +183,7 @@ fn interrupted(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::Interrupted
}

#[cfg(target_os = "wasi")]
#[cfg(all(target_os = "wasi", not(feature = "wasmedge")))]
fn main() {
panic!("can't bind to an address with wasi")
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ mod interest;
mod poll;
mod sys;
mod token;
#[cfg(not(target_os = "wasi"))]
#[cfg(any(not(target_os = "wasi"), feature = "wasmedge"))]
mod waker;

pub mod event;
Expand All @@ -66,7 +66,7 @@ pub use event::Events;
pub use interest::Interest;
pub use poll::{Poll, Registry};
pub use token::Token;
#[cfg(not(target_os = "wasi"))]
#[cfg(any(not(target_os = "wasi"), feature = "wasmedge"))]
pub use waker::Waker;

#[cfg(all(unix, feature = "os-ext"))]
Expand Down
76 changes: 59 additions & 17 deletions src/net/tcp/listener.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
use std::net::{self, SocketAddr};
use crate::io_source::IoSource;
use crate::net::TcpStream;
#[cfg(unix)]
use crate::sys::tcp::set_reuseaddr;
#[cfg(not(feature = "wasmedge"))]
use crate::sys::{
self,
tcp::{bind, listen, new_for_addr},
};
use crate::{event, Interest, Registry, Token};
#[cfg(not(feature = "wasmedge"))]
use std::net;
use std::net::SocketAddr;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(target_os = "wasi")]
use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
use std::{fmt, io};

use crate::io_source::IoSource;
use crate::net::TcpStream;
#[cfg(unix)]
use crate::sys::tcp::set_reuseaddr;
#[cfg(not(target_os = "wasi"))]
use crate::sys::tcp::{bind, listen, new_for_addr};
use crate::{event, sys, Interest, Registry, Token};

/// A structure representing a socket server
///
/// # Examples
Expand Down Expand Up @@ -42,7 +45,10 @@ use crate::{event, sys, Interest, Registry, Token};
/// # }
/// ```
pub struct TcpListener {
#[cfg(not(feature = "wasmedge"))]
inner: IoSource<net::TcpListener>,
#[cfg(feature = "wasmedge")]
inner: IoSource<wasmedge_wasi_socket::TcpListener>,
}

impl TcpListener {
Expand All @@ -55,7 +61,8 @@ impl TcpListener {
/// 2. Set the `SO_REUSEADDR` option on the socket on Unix.
/// 3. Bind the socket to the specified address.
/// 4. Calls `listen` on the socket to prepare it to receive new connections.
#[cfg(not(target_os = "wasi"))]
// #[cfg(not(target_os = "wasi"))]
#[cfg(not(feature = "wasmedge"))]
pub fn bind(addr: SocketAddr) -> io::Result<TcpListener> {
let socket = new_for_addr(addr)?;
#[cfg(unix)]
Expand All @@ -78,18 +85,36 @@ impl TcpListener {
Ok(listener)
}

/// bind wasi
#[cfg(feature = "wasmedge")]
pub fn bind(addr: SocketAddr) -> io::Result<TcpListener> {
let inner = wasmedge_wasi_socket::TcpListener::bind(addr, true)?;
Ok(TcpListener {
inner: IoSource::new(inner),
})
}

/// Creates a new `TcpListener` from a standard `net::TcpListener`.
///
/// This function is intended to be used to wrap a TCP listener from the
/// standard library in the Mio equivalent. The conversion assumes nothing
/// about the underlying listener; ; it is left up to the user to set it
/// in non-blocking mode.
#[cfg(not(feature = "wasmedge"))]
pub fn from_std(listener: net::TcpListener) -> TcpListener {
TcpListener {
inner: IoSource::new(listener),
}
}

/// fromstd wasi
#[cfg(feature = "wasmedge")]
pub fn from_std(listener: wasmedge_wasi_socket::TcpListener) -> TcpListener {
TcpListener {
inner: IoSource::new(listener),
}
}

/// Accepts a new `TcpStream`.
///
/// This may return an `Err(e)` where `e.kind()` is
Expand All @@ -99,22 +124,33 @@ impl TcpListener {
/// If an accepted stream is returned, the remote address of the peer is
/// returned along with it.
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
self.inner.do_io(|inner| {
#[cfg(not(feature = "wasmedge"))]
return self.inner.do_io(|inner| {
sys::tcp::accept(inner).map(|(stream, addr)| (TcpStream::from_std(stream), addr))
})
});
#[cfg(feature = "wasmedge")]
return self.inner.do_io(|inner| {
self.inner
.accept(true)
.map(|(stream, addr)| (TcpStream::from_std(stream), addr))
});
}

/// Returns the local socket address of this listener.
#[cfg(not(feature = "wasmedge"))]
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.local_addr()
return self.inner.local_addr();
}

/// Sets the value for the `IP_TTL` option on this socket.
///
/// This value sets the time-to-live field that is used in every packet sent
/// from this socket.
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.inner.set_ttl(ttl)
#[cfg(not(feature = "wasmedge"))]
return self.inner.set_ttl(ttl);
#[cfg(feature = "wasmedge")]
Ok(())
}

/// Gets the value of the `IP_TTL` option for this socket.
Expand All @@ -123,7 +159,10 @@ impl TcpListener {
///
/// [link]: #method.set_ttl
pub fn ttl(&self) -> io::Result<u32> {
self.inner.ttl()
#[cfg(not(feature = "wasmedge"))]
return self.inner.ttl();
#[cfg(feature = "wasmedge")]
Ok(0)
}

/// Get the value of the `SO_ERROR` option on this socket.
Expand All @@ -132,7 +171,10 @@ impl TcpListener {
/// the field in the process. This can be useful for checking errors between
/// calls.
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.inner.take_error()
#[cfg(not(feature = "wasmedge"))]
return self.inner.take_error();
#[cfg(feature = "wasmedge")]
Ok(None)
}
}

Expand Down
55 changes: 48 additions & 7 deletions src/net/tcp/stream.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::fmt;
use std::io::{self, IoSlice, IoSliceMut, Read, Write};
use std::net::{self, Shutdown, SocketAddr};
#[cfg(not(feature = "wasmedge"))]
use std::net;
use std::net::{Shutdown, SocketAddr};
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
#[cfg(target_os = "wasi")]
Expand Down Expand Up @@ -46,7 +48,10 @@ use crate::{event, Interest, Registry, Token};
/// # }
/// ```
pub struct TcpStream {
#[cfg(not(feature = "wasmedge"))]
inner: IoSource<net::TcpStream>,
#[cfg(feature = "wasmedge")]
inner: IoSource<wasmedge_wasi_socket::TcpStream>,
}

impl TcpStream {
Expand Down Expand Up @@ -91,6 +96,15 @@ impl TcpStream {
Ok(stream)
}

/// connect wasi
#[cfg(all(target_os = "wasi", feature = "wasmedge"))]
pub fn connect(addr: SocketAddr) -> io::Result<TcpStream> {
let inner = wasmedge_wasi_socket::TcpStream::connect(addr)?;
Ok(TcpStream {
inner: IoSource::new(inner),
})
}

/// Creates a new `TcpStream` from a standard `net::TcpStream`.
///
/// This function is intended to be used to wrap a TCP stream from the
Expand All @@ -103,12 +117,21 @@ impl TcpStream {
/// The TCP stream here will not have `connect` called on it, so it
/// should already be connected via some other means (be it manually, or
/// the standard library).
#[cfg(not(feature = "wasmedge"))]
pub fn from_std(stream: net::TcpStream) -> TcpStream {
TcpStream {
inner: IoSource::new(stream),
}
}

/// from std wasi
#[cfg(feature = "wasmedge")]
pub fn from_std(stream: wasmedge_wasi_socket::TcpStream) -> TcpStream {
TcpStream {
inner: IoSource::new(stream),
}
}

/// Returns the socket address of the remote peer of this TCP connection.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.inner.peer_addr()
Expand Down Expand Up @@ -142,7 +165,10 @@ impl TcpStream {
/// by receiving an (writable) event. Trying to set `nodelay` on an
/// unconnected `TcpStream` is unspecified behavior.
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.inner.set_nodelay(nodelay)
#[cfg(not(feature = "wasmedge"))]
return self.inner.set_nodelay(nodelay);
#[cfg(feature = "wasmedge")]
Ok(())
}

/// Gets the value of the `TCP_NODELAY` option on this socket.
Expand All @@ -157,7 +183,10 @@ impl TcpStream {
/// by receiving an (writable) event. Trying to get `nodelay` on an
/// unconnected `TcpStream` is unspecified behavior.
pub fn nodelay(&self) -> io::Result<bool> {
self.inner.nodelay()
#[cfg(not(feature = "wasmedge"))]
return self.inner.nodelay();
#[cfg(feature = "wasmedge")]
Ok(true)
}

/// Sets the value for the `IP_TTL` option on this socket.
Expand All @@ -171,7 +200,10 @@ impl TcpStream {
/// by receiving an (writable) event. Trying to set `ttl` on an
/// unconnected `TcpStream` is unspecified behavior.
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.inner.set_ttl(ttl)
#[cfg(not(feature = "wasmedge"))]
return self.inner.set_ttl(ttl);
#[cfg(feature = "wasmedge")]
Ok(())
}

/// Gets the value of the `IP_TTL` option for this socket.
Expand All @@ -186,7 +218,10 @@ impl TcpStream {
///
/// [link]: #method.set_ttl
pub fn ttl(&self) -> io::Result<u32> {
self.inner.ttl()
#[cfg(not(feature = "wasmedge"))]
return self.inner.ttl();
#[cfg(feature = "wasmedge")]
Ok(0)
}

/// Get the value of the `SO_ERROR` option on this socket.
Expand All @@ -195,7 +230,10 @@ impl TcpStream {
/// the field in the process. This can be useful for checking errors between
/// calls.
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.inner.take_error()
#[cfg(not(feature = "wasmedge"))]
return self.inner.take_error();
#[cfg(feature = "wasmedge")]
Ok(None)
}

/// Receives data on the socket from the remote address to which it is
Expand All @@ -205,7 +243,10 @@ impl TcpStream {
/// Successive calls return the same data. This is accomplished by passing
/// `MSG_PEEK` as a flag to the underlying recv system call.
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.peek(buf)
#[cfg(not(feature = "wasmedge"))]
return self.inner.peek(buf);
#[cfg(feature = "wasmedge")]
Ok(0)
}

/// Execute an I/O operation ensuring that the socket receives more events
Expand Down
2 changes: 1 addition & 1 deletion src/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ impl Registry {

/// Internal check to ensure only a single `Waker` is active per [`Poll`]
/// instance.
#[cfg(all(debug_assertions, not(target_os = "wasi")))]
#[cfg(debug_assertions)]
pub(crate) fn register_waker(&self) {
assert!(
!self.selector.register_waker(),
Expand Down
2 changes: 1 addition & 1 deletion src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ cfg_os_poll! {
#[cfg(target_os = "wasi")]
cfg_os_poll! {
mod wasi;
pub(crate) use self::wasi::*;
pub use self::wasi::*;
}

cfg_not_os_poll! {
Expand Down
Loading

0 comments on commit b73a96c

Please sign in to comment.