From 0b6375e0716a2c0c4a245ec04d383a43b8ec6da7 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 4 Feb 2022 10:45:48 +0100 Subject: [PATCH] Add networking for target_os = "wasi" With * https://github.com/bytecodealliance/wasmtime/pull/3711 * https://github.com/rust-lang/rust/pull/93158 merged, mio can have limited support for networking for the `wasm32-wasi` target. Signed-off-by: Harald Hoyer --- src/net/tcp/listener.rs | 33 +++++++++++++++++++++-- src/net/tcp/stream.rs | 31 ++++++++++++++++++++- src/net/udp.rs | 29 ++++++++++++++++++++ src/sys/wasi/mod.rs | 6 +++++ src/sys/wasi/net.rs | 60 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 src/sys/wasi/net.rs diff --git a/src/net/tcp/listener.rs b/src/net/tcp/listener.rs index 21bffbaff..2a5f4b2e6 100644 --- a/src/net/tcp/listener.rs +++ b/src/net/tcp/listener.rs @@ -1,13 +1,15 @@ use std::net::{self, 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)] +#[cfg(any(unix, target_os = "wasi"))] use crate::sys::tcp::set_reuseaddr; use crate::sys::tcp::{bind, listen, new_for_addr}; use crate::{event, sys, Interest, Registry, Token}; @@ -54,7 +56,7 @@ impl TcpListener { /// 4. Calls `listen` on the socket to prepare it to receive new connections. pub fn bind(addr: SocketAddr) -> io::Result { let socket = new_for_addr(addr)?; - #[cfg(unix)] + #[cfg(any(unix, target_os = "wasi"))] let listener = unsafe { TcpListener::from_raw_fd(socket) }; #[cfg(windows)] let listener = unsafe { TcpListener::from_raw_socket(socket as _) }; @@ -215,3 +217,30 @@ impl FromRawSocket for TcpListener { TcpListener::from_std(FromRawSocket::from_raw_socket(socket)) } } + +#[cfg(target_os = "wasi")] +impl IntoRawFd for TcpListener { + fn into_raw_fd(self) -> RawFd { + self.inner.into_inner().into_raw_fd() + } +} + +#[cfg(target_os = "wasi")] +impl AsRawFd for TcpListener { + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } +} + +#[cfg(target_os = "wasi")] +impl FromRawFd for TcpListener { + /// Converts a `RawFd` to a `TcpListener`. + /// + /// # Notes + /// + /// The caller is responsible for ensuring that the socket is in + /// non-blocking mode. + unsafe fn from_raw_fd(fd: RawFd) -> TcpListener { + TcpListener::from_std(FromRawFd::from_raw_fd(fd)) + } +} diff --git a/src/net/tcp/stream.rs b/src/net/tcp/stream.rs index 029f186b4..fe6387e7a 100644 --- a/src/net/tcp/stream.rs +++ b/src/net/tcp/stream.rs @@ -3,6 +3,8 @@ use std::io::{self, IoSlice, IoSliceMut, Read, Write}; use std::net::{self, Shutdown, 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}; @@ -75,7 +77,7 @@ impl TcpStream { /// [read interest]: Interest::READABLE pub fn connect(addr: SocketAddr) -> io::Result { let socket = new_for_addr(addr)?; - #[cfg(unix)] + #[cfg(any(unix, target_os = "wasi"))] let stream = unsafe { TcpStream::from_raw_fd(socket) }; #[cfg(windows)] let stream = unsafe { TcpStream::from_raw_socket(socket as _) }; @@ -332,3 +334,30 @@ impl FromRawSocket for TcpStream { TcpStream::from_std(FromRawSocket::from_raw_socket(socket)) } } + +#[cfg(target_os = "wasi")] +impl IntoRawFd for TcpStream { + fn into_raw_fd(self) -> RawFd { + self.inner.into_inner().into_raw_fd() + } +} + +#[cfg(target_os = "wasi")] +impl AsRawFd for TcpStream { + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } +} + +#[cfg(target_os = "wasi")] +impl FromRawFd for TcpStream { + /// Converts a `RawFd` to a `TcpStream`. + /// + /// # Notes + /// + /// The caller is responsible for ensuring that the socket is in + /// non-blocking mode. + unsafe fn from_raw_fd(fd: RawFd) -> TcpStream { + TcpStream::from_std(FromRawFd::from_raw_fd(fd)) + } +} diff --git a/src/net/udp.rs b/src/net/udp.rs index 8cfe4e456..6f166f786 100644 --- a/src/net/udp.rs +++ b/src/net/udp.rs @@ -16,6 +16,8 @@ use std::net; use std::net::{Ipv4Addr, Ipv6Addr, 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}; @@ -633,3 +635,30 @@ impl FromRawSocket for UdpSocket { UdpSocket::from_std(FromRawSocket::from_raw_socket(socket)) } } + +#[cfg(target_os = "wasi")] +impl IntoRawFd for UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.inner.into_inner().into_raw_fd() + } +} + +#[cfg(target_os = "wasi")] +impl AsRawFd for UdpSocket { + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } +} + +#[cfg(target_os = "wasi")] +impl FromRawFd for UdpSocket { + /// Converts a `RawFd` to a `UdpSocket`. + /// + /// # Notes + /// + /// The caller is responsible for ensuring that the socket is in + /// non-blocking mode. + unsafe fn from_raw_fd(fd: RawFd) -> UdpSocket { + UdpSocket::from_std(FromRawFd::from_raw_fd(fd)) + } +} diff --git a/src/sys/wasi/mod.rs b/src/sys/wasi/mod.rs index 17b5bac5c..c1009043e 100644 --- a/src/sys/wasi/mod.rs +++ b/src/sys/wasi/mod.rs @@ -22,6 +22,12 @@ use std::time::Duration; use crate::{Interest, Token}; +cfg_net! { + mod net; + + pub(crate) use net::{tcp, udp}; +} + /// Unique id for use as `SelectorId`. #[cfg(debug_assertions)] static NEXT_ID: AtomicUsize = AtomicUsize::new(1); diff --git a/src/sys/wasi/net.rs b/src/sys/wasi/net.rs new file mode 100644 index 000000000..c35410eca --- /dev/null +++ b/src/sys/wasi/net.rs @@ -0,0 +1,60 @@ +#![allow(dead_code)] + +use std::io; + +/// A lot of function are not support on Wasi, this function returns a +/// consistent error when calling those functions. +fn unsupported() -> io::Error { + io::Error::new(io::ErrorKind::Other, "not supported on wasi") +} + +pub(crate) mod tcp { + use std::io; + use std::net; + + use super::unsupported; + + pub type TcpSocket = wasi::Fd; + + pub(crate) fn new_for_addr(_address: net::SocketAddr) -> io::Result { + Err(unsupported()) + } + + pub(crate) fn bind(_: &net::TcpListener, _: net::SocketAddr) -> io::Result<()> { + Ok(()) + } + + pub(crate) fn connect(_: &net::TcpStream, _: net::SocketAddr) -> io::Result { + Err(unsupported()) + } + + pub(crate) fn listen(_: &net::TcpListener, _: u32) -> io::Result<()> { + Ok(()) + } + + pub(crate) fn set_reuseaddr(_: &net::TcpListener, _: bool) -> io::Result<()> { + Ok(()) + } + pub(crate) fn accept( + listener: &net::TcpListener, + ) -> io::Result<(net::TcpStream, net::SocketAddr)> { + let res = listener.accept(); + res + } +} + +pub(crate) mod udp { + use std::io; + use std::net::{self, SocketAddr}; + use std::os::wasi::io::FromRawFd; + + //use super::unsupported; + + pub(crate) fn bind(_: SocketAddr) -> io::Result { + Ok(unsafe { net::UdpSocket::from_raw_fd(0) }) + } + + pub(crate) fn only_v6(_socket: &net::UdpSocket) -> io::Result { + Ok(false) + } +}