From ebdbe6e4c7ef368599e18f03439a7b8592208c50 Mon Sep 17 00:00:00 2001 From: Gaukas Wang Date: Mon, 11 Sep 2023 16:56:33 -0600 Subject: [PATCH 1/2] new: Add WasiCtx Reflecting C-API changes made in https://github.com/bytecodealliance/wasmtime/pull/7001 by adding incomplete implementation for `WasiCtx`: - `func (store *Store) GetWasiCtx() *WasiCtx` - `func (c *WasiConfig) PreopenTCPSocket(innerFD uint32, hostPort string) error`*: not a part of `WasiCtx`, but adding it since it was already there in C-API. - `type WasiFileAccessMode uint32`* - `type WasiCtx struct` - `(*WasiCtx).InsertFile(guestFD uint32, file *os.File, accessMode WasiFileAccessMode)` - `(*WasiCtx).PushFile(file *os.File, accessMode WasiFileAccessMode) (uint32, error)` *: Credit goes to @jmwample. --------- Co-authored-by: jmwample --- store.go | 7 ++++++ wasi.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/store.go b/store.go index b19ae10..d1ea65b 100644 --- a/store.go +++ b/store.go @@ -113,6 +113,13 @@ func (store *Store) SetWasi(wasi *WasiConfig) { runtime.KeepAlive(store) } +func (store *Store) GetWasiCtx() *WasiCtx { + C.wasmtime_context_set_default_wasi_if_not_exist(store.Context()) + ret := C.wasmtime_context_get_wasi_ctx(store.Context()) + // runtime.KeepAlive(store) + return &WasiCtx{_ptr: ret} +} + // 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..8563355 100644 --- a/wasi.go +++ b/wasi.go @@ -2,9 +2,11 @@ package wasmtime // #include // #include +// #include import "C" import ( "errors" + "os" "runtime" "unsafe" ) @@ -148,3 +150,68 @@ 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 +) + +type WasiCtx struct { + _ptr *C.wasi_ctx_t +} + +func (ctx *WasiCtx) ptr() *C.wasi_ctx_t { + ret := ctx._ptr + maybeGC() + return ret +} + +func (ctx *WasiCtx) InsertFile(guestFD uint32, file *os.File, accessMode WasiFileAccessMode) { + C.wasi_ctx_insert_file(ctx.ptr(), C.uint32_t(guestFD), C.uint32_t(file.Fd()), C.uint32_t(accessMode)) + runtime.KeepAlive(ctx) + 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.wasi_ctx_push_file(ctx.ptr(), C.uint32_t(file.Fd()), C.uint32_t(accessMode), &c_fd) + runtime.KeepAlive(ctx) + runtime.KeepAlive(file) + if err != nil { + return 0, mkError(err) + } + + return uint32(c_fd), nil +} From 0fd811718dbfe3b21b3073c6fa0fd34fb4ac245c Mon Sep 17 00:00:00 2001 From: Gaukas Wang Date: Wed, 13 Sep 2023 16:32:39 -0600 Subject: [PATCH 2/2] update: reimplement WasiCtx Redesign `WasiCtx` to wrap a *Store. Revise the member functions to call `wasmtime_context_*` functions from C-API. --- store.go | 13 ++++++++----- wasi.go | 21 ++++++++++----------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/store.go b/store.go index d1ea65b..e1cd6e2 100644 --- a/store.go +++ b/store.go @@ -113,11 +113,14 @@ func (store *Store) SetWasi(wasi *WasiConfig) { runtime.KeepAlive(store) } -func (store *Store) GetWasiCtx() *WasiCtx { - C.wasmtime_context_set_default_wasi_if_not_exist(store.Context()) - ret := C.wasmtime_context_get_wasi_ctx(store.Context()) - // runtime.KeepAlive(store) - return &WasiCtx{_ptr: ret} +// 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 diff --git a/wasi.go b/wasi.go index 8563355..8434232 100644 --- a/wasi.go +++ b/wasi.go @@ -1,6 +1,7 @@ package wasmtime // #include +// #include // #include // #include import "C" @@ -186,19 +187,17 @@ const ( 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 { - _ptr *C.wasi_ctx_t -} - -func (ctx *WasiCtx) ptr() *C.wasi_ctx_t { - ret := ctx._ptr - maybeGC() - return ret + store *Store } func (ctx *WasiCtx) InsertFile(guestFD uint32, file *os.File, accessMode WasiFileAccessMode) { - C.wasi_ctx_insert_file(ctx.ptr(), C.uint32_t(guestFD), C.uint32_t(file.Fd()), C.uint32_t(accessMode)) - runtime.KeepAlive(ctx) + 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) } @@ -206,8 +205,8 @@ func (ctx *WasiCtx) PushFile(file *os.File, accessMode WasiFileAccessMode) (uint var fd uint32 c_fd := C.uint32_t(fd) - err := C.wasi_ctx_push_file(ctx.ptr(), C.uint32_t(file.Fd()), C.uint32_t(accessMode), &c_fd) - runtime.KeepAlive(ctx) + 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)