Skip to content
This repository has been archived by the owner on Nov 10, 2022. It is now read-only.

Redirect input/output to socket #4

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
target = "wasm32-wasi"
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ edition = "2018"

[dependencies]
getrandom = "0.2"
wasi-socket = { path = "socket-bindings" }
6 changes: 6 additions & 0 deletions bundle/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
stdio:
stdin: "null"
stdout: "null"
stderr: "null"
listen_address: "localhost:5000"
1 change: 1 addition & 0 deletions rust-toolchain
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nightly
9 changes: 9 additions & 0 deletions socket-bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "wasi-socket"
version = "0.1.0"
authors = ["Daiki Ueno <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
47 changes: 47 additions & 0 deletions socket-bindings/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use super::Errno;
use core::fmt;
use core::num::NonZeroU16;
use crate::strerror;

/// A raw error returned by wasi-socket APIs, internally containing a 16-bit
/// error code.
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub struct Error {
code: NonZeroU16,
}

impl Error {
/// Constructs a new error from a raw error code, returning `None` if the
/// error code is zero (which means success).
pub fn from_raw_error(error: Errno) -> Option<Error> {
Some(Error {
code: NonZeroU16::new(error)?,
})
}

/// Returns the raw error code that this error represents.
pub fn raw_error(&self) -> u16 {
self.code.get()
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} (error {})", strerror(self.code.get()), self.code)?;
Ok(())
}
}

impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Error")
.field("code", &self.code)
.field("message", &strerror(self.code.get()))
.finish()
}
}

#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "std")]
impl std::error::Error for Error {}
269 changes: 269 additions & 0 deletions socket-bindings/src/generated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
// This file is automatically generated, DO NOT EDIT
//
// To regenerate this file run the `crates/witx-bindgen` command

use core::mem::MaybeUninit;

pub use crate::error::Error;
pub type Result<T, E = Error> = core::result::Result<T, E>;
pub type Errno = u16;
/// No error occurred. System call completed successfully.
pub const ERRNO_SUCCESS: Errno = 0;
/// Argument list too long.
pub const ERRNO_2BIG: Errno = 1;
/// Permission denied.
pub const ERRNO_ACCESS: Errno = 2;
/// Address in use.
pub const ERRNO_ADDRINUSE: Errno = 3;
/// Address not available.
pub const ERRNO_ADDRNOTAVAIL: Errno = 4;
/// Address family not supported.
pub const ERRNO_AFNOSUPPORT: Errno = 5;
/// Resource unavailable, or operation would block.
pub const ERRNO_AGAIN: Errno = 6;
/// Connection already in progress.
pub const ERRNO_ALREADY: Errno = 7;
/// Bad file descriptor.
pub const ERRNO_BADF: Errno = 8;
/// Bad message.
pub const ERRNO_BADMSG: Errno = 9;
/// Device or resource busy.
pub const ERRNO_BUSY: Errno = 10;
/// Operation canceled.
pub const ERRNO_CANCELED: Errno = 11;
/// No child processes.
pub const ERRNO_CHILD: Errno = 12;
/// Connection aborted.
pub const ERRNO_CONNABORTED: Errno = 13;
/// Connection refused.
pub const ERRNO_CONNREFUSED: Errno = 14;
/// Connection reset.
pub const ERRNO_CONNRESET: Errno = 15;
/// Resource deadlock would occur.
pub const ERRNO_DEADLK: Errno = 16;
/// Destination address required.
pub const ERRNO_DESTADDRREQ: Errno = 17;
/// Mathematics argument out of domain of function.
pub const ERRNO_DOM: Errno = 18;
/// Reserved.
pub const ERRNO_DQUOT: Errno = 19;
/// File exists.
pub const ERRNO_EXIST: Errno = 20;
/// Bad address.
pub const ERRNO_FAULT: Errno = 21;
/// File too large.
pub const ERRNO_FBIG: Errno = 22;
/// Host is unreachable.
pub const ERRNO_HOSTUNREACH: Errno = 23;
/// Identifier removed.
pub const ERRNO_IDRM: Errno = 24;
/// Illegal byte sequence.
pub const ERRNO_ILSEQ: Errno = 25;
/// Operation in progress.
pub const ERRNO_INPROGRESS: Errno = 26;
/// Interrupted function.
pub const ERRNO_INTR: Errno = 27;
/// Invalid argument.
pub const ERRNO_INVAL: Errno = 28;
/// I/O error.
pub const ERRNO_IO: Errno = 29;
/// Socket is connected.
pub const ERRNO_ISCONN: Errno = 30;
/// Is a directory.
pub const ERRNO_ISDIR: Errno = 31;
/// Too many levels of symbolic links.
pub const ERRNO_LOOP: Errno = 32;
/// File descriptor value too large.
pub const ERRNO_MFILE: Errno = 33;
/// Too many links.
pub const ERRNO_MLINK: Errno = 34;
/// Message too large.
pub const ERRNO_MSGSIZE: Errno = 35;
/// Reserved.
pub const ERRNO_MULTIHOP: Errno = 36;
/// Filename too long.
pub const ERRNO_NAMETOOLONG: Errno = 37;
/// Network is down.
pub const ERRNO_NETDOWN: Errno = 38;
/// Connection aborted by network.
pub const ERRNO_NETRESET: Errno = 39;
/// Network unreachable.
pub const ERRNO_NETUNREACH: Errno = 40;
/// Too many files open in system.
pub const ERRNO_NFILE: Errno = 41;
/// No buffer space available.
pub const ERRNO_NOBUFS: Errno = 42;
/// No such device.
pub const ERRNO_NODEV: Errno = 43;
/// No such file or directory.
pub const ERRNO_NOENT: Errno = 44;
/// Executable file format error.
pub const ERRNO_NOEXEC: Errno = 45;
/// No locks available.
pub const ERRNO_NOLCK: Errno = 46;
/// Reserved.
pub const ERRNO_NOLINK: Errno = 47;
/// Not enough space.
pub const ERRNO_NOMEM: Errno = 48;
/// No message of the desired type.
pub const ERRNO_NOMSG: Errno = 49;
/// Protocol not available.
pub const ERRNO_NOPROTOOPT: Errno = 50;
/// No space left on device.
pub const ERRNO_NOSPC: Errno = 51;
/// Function not supported.
pub const ERRNO_NOSYS: Errno = 52;
/// The socket is not connected.
pub const ERRNO_NOTCONN: Errno = 53;
/// Not a directory or a symbolic link to a directory.
pub const ERRNO_NOTDIR: Errno = 54;
/// Directory not empty.
pub const ERRNO_NOTEMPTY: Errno = 55;
/// State not recoverable.
pub const ERRNO_NOTRECOVERABLE: Errno = 56;
/// Not a socket.
pub const ERRNO_NOTSOCK: Errno = 57;
/// Not supported, or operation not supported on socket.
pub const ERRNO_NOTSUP: Errno = 58;
/// Inappropriate I/O control operation.
pub const ERRNO_NOTTY: Errno = 59;
/// No such device or address.
pub const ERRNO_NXIO: Errno = 60;
/// Value too large to be stored in data type.
pub const ERRNO_OVERFLOW: Errno = 61;
/// Previous owner died.
pub const ERRNO_OWNERDEAD: Errno = 62;
/// Operation not permitted.
pub const ERRNO_PERM: Errno = 63;
/// Broken pipe.
pub const ERRNO_PIPE: Errno = 64;
/// Protocol error.
pub const ERRNO_PROTO: Errno = 65;
/// Protocol not supported.
pub const ERRNO_PROTONOSUPPORT: Errno = 66;
/// Protocol wrong type for socket.
pub const ERRNO_PROTOTYPE: Errno = 67;
/// Result too large.
pub const ERRNO_RANGE: Errno = 68;
/// Read-only file system.
pub const ERRNO_ROFS: Errno = 69;
/// Invalid seek.
pub const ERRNO_SPIPE: Errno = 70;
/// No such process.
pub const ERRNO_SRCH: Errno = 71;
/// Reserved.
pub const ERRNO_STALE: Errno = 72;
/// Connection timed out.
pub const ERRNO_TIMEDOUT: Errno = 73;
/// Text file busy.
pub const ERRNO_TXTBSY: Errno = 74;
/// Cross-device link.
pub const ERRNO_XDEV: Errno = 75;
/// Extension: Capabilities insufficient.
pub const ERRNO_NOTCAPABLE: Errno = 76;
pub(crate) fn strerror(code: u16) -> &'static str {
match code {
ERRNO_SUCCESS => "No error occurred. System call completed successfully.",
ERRNO_2BIG => "Argument list too long.",
ERRNO_ACCESS => "Permission denied.",
ERRNO_ADDRINUSE => "Address in use.",
ERRNO_ADDRNOTAVAIL => "Address not available.",
ERRNO_AFNOSUPPORT => "Address family not supported.",
ERRNO_AGAIN => "Resource unavailable, or operation would block.",
ERRNO_ALREADY => "Connection already in progress.",
ERRNO_BADF => "Bad file descriptor.",
ERRNO_BADMSG => "Bad message.",
ERRNO_BUSY => "Device or resource busy.",
ERRNO_CANCELED => "Operation canceled.",
ERRNO_CHILD => "No child processes.",
ERRNO_CONNABORTED => "Connection aborted.",
ERRNO_CONNREFUSED => "Connection refused.",
ERRNO_CONNRESET => "Connection reset.",
ERRNO_DEADLK => "Resource deadlock would occur.",
ERRNO_DESTADDRREQ => "Destination address required.",
ERRNO_DOM => "Mathematics argument out of domain of function.",
ERRNO_DQUOT => "Reserved.",
ERRNO_EXIST => "File exists.",
ERRNO_FAULT => "Bad address.",
ERRNO_FBIG => "File too large.",
ERRNO_HOSTUNREACH => "Host is unreachable.",
ERRNO_IDRM => "Identifier removed.",
ERRNO_ILSEQ => "Illegal byte sequence.",
ERRNO_INPROGRESS => "Operation in progress.",
ERRNO_INTR => "Interrupted function.",
ERRNO_INVAL => "Invalid argument.",
ERRNO_IO => "I/O error.",
ERRNO_ISCONN => "Socket is connected.",
ERRNO_ISDIR => "Is a directory.",
ERRNO_LOOP => "Too many levels of symbolic links.",
ERRNO_MFILE => "File descriptor value too large.",
ERRNO_MLINK => "Too many links.",
ERRNO_MSGSIZE => "Message too large.",
ERRNO_MULTIHOP => "Reserved.",
ERRNO_NAMETOOLONG => "Filename too long.",
ERRNO_NETDOWN => "Network is down.",
ERRNO_NETRESET => "Connection aborted by network.",
ERRNO_NETUNREACH => "Network unreachable.",
ERRNO_NFILE => "Too many files open in system.",
ERRNO_NOBUFS => "No buffer space available.",
ERRNO_NODEV => "No such device.",
ERRNO_NOENT => "No such file or directory.",
ERRNO_NOEXEC => "Executable file format error.",
ERRNO_NOLCK => "No locks available.",
ERRNO_NOLINK => "Reserved.",
ERRNO_NOMEM => "Not enough space.",
ERRNO_NOMSG => "No message of the desired type.",
ERRNO_NOPROTOOPT => "Protocol not available.",
ERRNO_NOSPC => "No space left on device.",
ERRNO_NOSYS => "Function not supported.",
ERRNO_NOTCONN => "The socket is not connected.",
ERRNO_NOTDIR => "Not a directory or a symbolic link to a directory.",
ERRNO_NOTEMPTY => "Directory not empty.",
ERRNO_NOTRECOVERABLE => "State not recoverable.",
ERRNO_NOTSOCK => "Not a socket.",
ERRNO_NOTSUP => "Not supported, or operation not supported on socket.",
ERRNO_NOTTY => "Inappropriate I/O control operation.",
ERRNO_NXIO => "No such device or address.",
ERRNO_OVERFLOW => "Value too large to be stored in data type.",
ERRNO_OWNERDEAD => "Previous owner died.",
ERRNO_PERM => "Operation not permitted.",
ERRNO_PIPE => "Broken pipe.",
ERRNO_PROTO => "Protocol error.",
ERRNO_PROTONOSUPPORT => "Protocol not supported.",
ERRNO_PROTOTYPE => "Protocol wrong type for socket.",
ERRNO_RANGE => "Result too large.",
ERRNO_ROFS => "Read-only file system.",
ERRNO_SPIPE => "Invalid seek.",
ERRNO_SRCH => "No such process.",
ERRNO_STALE => "Reserved.",
ERRNO_TIMEDOUT => "Connection timed out.",
ERRNO_TXTBSY => "Text file busy.",
ERRNO_XDEV => "Cross-device link.",
ERRNO_NOTCAPABLE => "Extension: Capabilities insufficient.",
_ => "Unknown error.",
}
}
pub type Fd = u32;
/// Accept an incoming connection.
///
/// ## Return
///
/// * `opened_fd` - The file descriptor that has been opened.
pub unsafe fn accept() -> Result<Fd> {
let mut opened_fd = MaybeUninit::uninit();
let rc = wasi_ephemeral_socket::accept(opened_fd.as_mut_ptr());
if let Some(err) = Error::from_raw_error(rc) {
Err(err)
} else {
Ok(opened_fd.assume_init())
}
}

pub mod wasi_ephemeral_socket {
use super::*;
#[link(wasm_import_module = "wasi_ephemeral_socket")]
extern "C" {
/// Accept an incoming connection.
pub fn accept(opened_fd: *mut Fd) -> Errno;
}
}
3 changes: 3 additions & 0 deletions socket-bindings/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod error;
mod generated;
pub use generated::*;
13 changes: 9 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
#![feature(wasi_ext)]

use std::ffi::CString;
use std::io::Read;
use std::io::prelude::*;
use std::os::wasi::prelude::*;

fn main() {
let mut buf = [0u8; 4];
let _ = getrandom::getrandom(&mut buf).unwrap();
let number = u32::from_le_bytes(buf);
let string = CString::new(format!("=={:08x}==", number)).unwrap();

println!("Press ENTER to reveal the secret...");
std::io::stdin().read_exact(&mut [0u8]).unwrap();
let socket_fd = unsafe { wasi_socket::accept().unwrap() };
let mut socket = unsafe { std::fs::File::from_raw_fd(socket_fd) };

println!("The secret is: {:?}", string);
socket.write_all(b"Press ENTER to reveal the secret...\n").unwrap();
socket.read_exact(&mut [0u8]).unwrap();
socket.write_all(format!("The secret is: {:?}\n", string).as_bytes()).unwrap();
}