Wawona Relay WASI P1 host imports: sockets, Wayland fd bridge, terminal. Rootshell-style reference.

Canonical developer reference for host imports linked by the Wawona Runtime (Relay import/wasm, product libwawona_wasm.a / wasm / wpm run).

Implementation: Relay/import/wasm/src/host.rs. Wayland how-to: Wayland wasm. Examples: Relay/import/wasm/examples/.

Vanilla WASI Preview 1 plus thin host modules where P1 has no sockets, no unix SCM_RIGHTS, and no TTY mode bit. Same documentation shape as Rootshell’s runtime ABI, with Wawona module names.

Model

PieceRole
WASI P1argv, environ, preopens, stdio, clocks, random, exit
wawona_socket (+ env alias)TCP/UDP/unix table, Wayland connect, SHM fd bridge, experimental VK board
wawona_terminal (+ env alias)raw/cooked bit, is_tty

Import modules. Prefer named modules (wawona_socket, wawona_terminal). Rust #[link(wasm_import_module = "env")] also works: the host registers every symbol on both the named module and env.

Fd spaces. Host socket / Wayland / SHM fds live in a separate table from WASI filesystem fds. Do not pass a wawona_socket_* fd to WASI fd_close, and do not pass a WASI fd to wawona_socket_close. Host fds start at 3 and grow.

Return value. Every call returns i32 errno: 0 success, else a WASI errno constant:

NameValueTypical use
EACCES2sendmsg / SCM_RIGHTS failed
EBADF8Unknown host fd
EINVAL28Bad args, OOB linear memory
EIO29Connect/read/write/interrupt failure
ENOSYS52Not implemented (TLS today)

Pointers are linear-memory offsets (i32). Out-params write little-endian i32 into guest memory.

Engines. Store Apple mobile through iOS 26: Wasmtime Pulley. macOS / Linux: Cranelift. iOS 27+ Mode A may use Wasmer WASIX in WebKit when linked. These host imports are the P1 Wasmtime path. Do not assume Cranelift or MAP_JIT in App Store IPAs.

Constants

#define AF_UNIX     1
#define AF_INET     2
#define AF_INET6    30
#define SOCK_STREAM 1
#define SOCK_DGRAM  2

wawona_socket — networking

WASI P1 has no sockets. Use this table for TCP/UDP. Wayland uses the same table for the display unix stream and SHM files.

wawona_socket_socket(domain, ty, fd_out) -> errno

Create a host fd.

domain / tyResult
AF_INET or AF_INET6 + SOCK_STREAMTCP slot (connect with connect_host)
AF_INET or AF_INET6 + SOCK_DGRAMUDP bound to 0.0.0.0:0
AF_UNIX + SOCK_STREAMPlaceholder until Wayland/unix connect path replaces it

Writes the new host fd to *fd_out. Other pairs → EINVAL.

wawona_socket_connect_host(fd, host, host_len, port) -> errno

TCP connect. host is UTF-8 hostname or IP literal of length host_len. Replaces the table entry for fd with a connected TcpStream (TCP_NODELAY on). Failure → EIO.

wawona_socket_send(fd, buf, len, sent_out) -> errno

Write up to len bytes from guest memory. Sets *sent_out to bytes written. Supports TCP, unix, and UDP table entries. Bad fd → EBADF.

wawona_socket_recv(fd, buf, len, recv_out) -> errno

Blocking read into guest memory. Sets *recv_out to bytes read (0 at EOF). Ctrl+C / guest interrupt returns EIO. A successful read with n > 0 refills Wasmtime fuel so a GUI event loop is not starved mid-frame.

wawona_socket_close(fd) -> errno

Drop the host table entry. EBADF if unknown.

wawona_socket_tls_connect_host(fd, host, host_len, port) -> errno

Always ENOSYS today. Use a guest TLS stack over TCP, or wait for a host TLS land.

Not exposed yet

bind / listen / accept / sendto / recvfrom / DNS helpers, setsockopt / poll / select, raw ICMP. Open an issue on Wawona/Relay if a store-safe knob is required.

wawona_socket — Wayland fd bridge

Not a custom draw API. Guests speak real Wayland wire protocol (wl_display, wl_shm, xdg_wm_base, …) into Wawona’s existing compositor socket (WAYLAND_DISPLAY). The host only supplies unix connect + anonymous SHM + SCM_RIGHTS (missing from WASI).

Env used by wawona_wayland_connect:

VariableDefault
XDG_RUNTIME_DIR/tmp/wawona-$UID
WAYLAND_DISPLAYwayland-0

Socket path: $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY.

wawona_wayland_connect(fd_out) -> errno

Unix-stream connect to the compositor. Writes a host fd to *fd_out. Failure → EIO.

wawona_wayland_shm_create(size, fd_out) -> errno

Allocate an anonymous file of size bytes (POSIX shm_open + unlink when available; else a temp file under XDG_RUNTIME_DIR). Writes host fd to *fd_out. size <= 0 → EINVAL.

wawona_wayland_shm_write(shm_fd, offset, buf, len) -> errno

Copy len bytes from guest memory into the SHM file at offset.

wawona_wayland_sendmsg(wl_fd, buf, len, scm_fd) -> errno

sendmsg on the Wayland unix fd: protocol bytes from guest memory, optional SCM_RIGHTS of scm_fd when scm_fd >= 0. Pass scm_fd = -1 for ordinary requests. This is how wl_shm.create_pool gets a real fd into the compositor.

wawona_wayland_shm_send(wl_fd, shm_fd) -> errno

Legacy helper: one dummy byte + SCM_RIGHTS of shm_fd. Prefer wawona_wayland_sendmsg with real protocol bytes (see the wayland-shm example).

Experimental Vulkan board

Lab / demo path. Not the store Wayland GUI contract. Prefer wl_shm for portable GUI (including watchOS SpriteKit present).

SymbolMeaning
wawona_vk_probe() -> i32Non-zero if board path available
wawona_vk_upload(desc) -> errnoUpload SPIR-V / verts / texture layers from a guest descriptor
wawona_vk_frame(desc) -> errnoRasterize into guest RGBA buffer

Descriptor layouts live in host.rs. Treat as unstable.

wawona_terminal — raw vs cooked

i32 wawona_terminal_set_raw(i32 enabled);  /* 0 cooked, 1 raw */
i32 wawona_terminal_is_tty(i32 fd);        /* 1 if fd is 0/1/2 */

set_raw stores a process-scoped bit the shell host can observe (TUIs). is_tty returns 1 for WASI fds 0–2, else 0. When the wasm process exits, the host restores cooked behaviour.

Language bindings

#[link(wasm_import_module = "wawona_socket")]
extern "C" {
    fn wawona_wayland_connect(fd_out: *mut i32) -> i32;
    fn wawona_wayland_shm_create(size: i32, fd_out: *mut i32) -> i32;
    fn wawona_wayland_shm_write(shm_fd: i32, offset: i32, buf: *const u8, len: i32) -> i32;
    fn wawona_wayland_sendmsg(wl_fd: i32, buf: *const u8, len: i32, scm_fd: i32) -> i32;
    fn wawona_socket_recv(fd: i32, buf: *mut u8, len: i32, n_out: *mut i32) -> i32;
}

Go: //go:wasmimport wawona_socket wawona_wayland_connect. Swift: @_extern(wasm, module: "wawona_socket", name: "wawona_wayland_connect").

ExampleRepo path
CLI + socketsRelay/import/wasm/examples/rust
Wayland SHM interactiveRelay/import/wasm/examples/wayland-shm
Minimal GUI smokeRelay/import/wasm/examples/hello-wasi-gui
Catalog Wayland appchess-wawona (guide)
WASI P2Relay/import/wasm/examples/wasip2 (standard wasi:*, not this host ABI)

C host entry (native side)

Product link (wawona_wasm.h):

  • wawona_wasm_can_run(path)
  • wawona_wasm_run(argc, argv)
  • wawona_terminal_raw_enabled()

Package CLI: wpm. Catalog: repo.wawona.io/wasm/v1. User-facing: WASM / WASI, Packages.

Hard rejects

  • Custom draw host instead of Wayland wire protocol for GUI
  • Claiming TLS host ABI works (ENOSYS)
  • Mixing WASI fds and host socket fds
  • Cranelift / MAP_JIT / Mode B engines in App Store IPA
  • Documenting Rootshell module names (rootshell_*) as Wawona imports