diff --git a/store.go b/store.go index b19ae10..e1cd6e2 100644 --- a/store.go +++ b/store.go @@ -113,6 +113,16 @@ func (store *Store) SetWasi(wasi *WasiConfig) { runtime.KeepAlive(store) } +// WasiCtx exports the `WasiCtx` within this store. +// +// It essentially wraps the `Store` and therefore can be called for multiple +// times and at any time, even if `SetWasi` has not been called yet. +// However, functions within the `WasiCtx` can be invoked only after +// `SetWasi` has been called on the store. +func (store *Store) WasiCtx() *WasiCtx { + return &WasiCtx{store} +} + // Implementation of the `Storelike` interface func (store *Store) Context() *C.wasmtime_context_t { ret := C.wasmtime_store_context(store._ptr) diff --git a/wasi.go b/wasi.go index 21900ff..8434232 100644 --- a/wasi.go +++ b/wasi.go @@ -1,10 +1,13 @@ package wasmtime // #include +// #include // #include +// #include import "C" import ( "errors" + "os" "runtime" "unsafe" ) @@ -148,3 +151,66 @@ func (c *WasiConfig) PreopenDir(path, guestPath string) error { return errors.New("failed to preopen directory") } + +// PreopenTCPSocket configures a "preopened" tcp listen socket to be available to +// WASI APIs after build. +// +// By default WASI programs do not have access to open up network sockets on the +// host. This API can be used to grant WASI programs access to a network socket +// file descriptor on the host. +// +// The fd_num argument is the number of the file descriptor by which it will be +// known in WASM and the host_port is the IP address and port (e.g. +// "127.0.0.1:8080") requested to listen on. +func (c *WasiConfig) PreopenTCPSocket(innerFD uint32, hostPort string) error { + + c_hostPort := C.CString(hostPort) + + ok := C.wasi_config_preopen_socket(c.ptr(), C.uint32_t(innerFD), c_hostPort) + runtime.KeepAlive(c) + C.free(unsafe.Pointer(&hostPort)) + if ok { + return nil + } + return errors.New("failed to conifgure preopen tcp socket") +} + +// FileAccessMode Indicates whether the file-like object being inserted into the +// WASI configuration (by PushFile and InsertFile) can be used to read, write, +// or both using bitflags. This seems to be a wasmtime specific mapping as it +// does not match syscall.O_RDONLY, O_WRONLY, etc. +type WasiFileAccessMode uint32 + +const ( + READ WasiFileAccessMode = 1 << iota + WRITE + READ_WRITE = READ | WRITE +) + +// WasiCtx maps to the Rust `WasiCtx` type. +// +// Instead of wrapping a pointer to the type directly, this type is a wrapper +// around a Store in order to call the `wasmtime_context_*` functions. +type WasiCtx struct { + store *Store +} + +func (ctx *WasiCtx) InsertFile(guestFD uint32, file *os.File, accessMode WasiFileAccessMode) { + C.wasmtime_context_insert_file(ctx.store.Context(), C.uint32_t(guestFD), unsafe.Pointer(file.Fd()), C.uint32_t(accessMode)) + runtime.KeepAlive(ctx.store) + runtime.KeepAlive(file) +} + +func (ctx *WasiCtx) PushFile(file *os.File, accessMode WasiFileAccessMode) (uint32, error) { + var fd uint32 + c_fd := C.uint32_t(fd) + + err := C.wasmtime_context_push_file(ctx.store.Context(), unsafe.Pointer(file.Fd()), C.uint32_t(accessMode), &c_fd) + runtime.KeepAlive(ctx.store) + runtime.KeepAlive(file) + if err != nil { + return 0, mkError(err) + } + + return uint32(c_fd), nil +}