/* * Copyright (C) Andrew Clayton * Copyright (C) F5, Inc. */ #include #include #include #include #include #include #include #include #include "nxt_wasm.h" typedef struct nxt_wamr_ctx_s nxt_wamr_ctx_t; struct nxt_wamr_ctx_s { uint8_t *mod_buf; wasm_module_t module; wasm_module_inst_t module_inst; wasm_exec_env_t exec_env; }; static nxt_wamr_ctx_t nxt_wamr_ctx; static void nxt_wamr_err_msg(const char *fmt, ...) { char dstr[20]; time_t t; va_list args; struct tm *tmp; t = time(NULL); tmp = localtime(&t); if (tmp == NULL) { return; } strftime(dstr, sizeof(dstr), "%Y/%m/%d %T", tmp); fprintf(stderr, "%s [WAMR ERROR] %d ", dstr, getpid()); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); } static uint32_t nxt_wasm_get_init_mem_size(wasm_exec_env_t exec_env) { return NXT_WASM_MEM_SIZE; } static void nxt_wasm_response_end(wasm_exec_env_t exec_env) { nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env); nxt_wasm_do_response_end(ctx); } static void nxt_wasm_send_response(wasm_exec_env_t exec_env, uint32_t offset) { nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env); nxt_wasm_do_send_response(ctx, offset); } static void nxt_wasm_send_headers(wasm_exec_env_t exec_env, uint32_t offset) { nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env); nxt_wasm_do_send_headers(ctx, offset); } static void nxt_wasm_set_resp_status(wasm_exec_env_t exec_env, uint16_t status) { nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env); ctx->status = status; } static void nxt_wamr_execute_hook(const nxt_wasm_ctx_t *ctx, nxt_wasm_fh_t hook) { bool ok; const char *name = ctx->fh[hook].func_name; nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; const nxt_wasm_func_t *func = ctx->fh[hook].func; if (name == NULL) { return; } ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func, 0, NULL, 0, NULL); if (!ok) { nxt_wamr_err_msg("failed to call hook function [%s]. (%s)", name, wasm_runtime_get_exception(rt_ctx->module_inst)); } } static int nxt_wamr_execute_request(const nxt_wasm_ctx_t *ctx) { bool ok; uint32_t i = 0; wasm_val_t args[1] = { }; wasm_val_t results[1] = { }; nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_REQUEST].func; args[i].kind = WASM_I32; args[i++].of.i32 = ctx->baddr_off; ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func, 1, results, i, args); if (!ok) { nxt_wamr_err_msg("Failed to call function [->wasm_request_handler]. " "(%s)", wasm_runtime_get_exception(rt_ctx->module_inst)); return -1; } return results[0].of.i32; } static bool nxt_wamr_set_function_imports(void) { int nr_funcs; bool ok; static NativeSymbol import_functions[] = { EXPORT_WASM_API_WITH_SIG(nxt_wasm_get_init_mem_size, "()i"), EXPORT_WASM_API_WITH_SIG(nxt_wasm_response_end, "()"), EXPORT_WASM_API_WITH_SIG(nxt_wasm_send_response, "(i)"), EXPORT_WASM_API_WITH_SIG(nxt_wasm_send_headers, "(i)"), EXPORT_WASM_API_WITH_SIG(nxt_wasm_set_resp_status, "(i)"), }; nr_funcs = sizeof(import_functions) / sizeof(NativeSymbol); ok = wasm_runtime_register_natives("env", import_functions, nr_funcs); if (!ok) { return false; } return true; } static int nxt_wamr_get_function_exports(nxt_wasm_ctx_t *ctx) { int i; nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; for (i = 0; i < NXT_WASM_FH_NR; i++) { if (ctx->fh[i].func_name == NULL) { continue; } ctx->fh[i].func = wasm_runtime_lookup_function(rt_ctx->module_inst, ctx->fh[i].func_name, NULL); if (ctx->fh[i].func == NULL) { return -1; } } return 0; } static void nxt_wamr_wasi_init(const nxt_wasm_ctx_t *ctx) { nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; wasm_runtime_set_wasi_args(rt_ctx->module, (const char **)ctx->dirs, ctx->nr_dirs, NULL, 0, NULL, 0, NULL, 0); } static int nxt_wamr_init_memory(nxt_wasm_ctx_t *ctx) { bool ok; uint32_t i = 0; wasm_val_t args[1] = { }; wasm_val_t results[1] = { }; nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_MALLOC].func; args[i].kind = WASM_I32; args[i++].of.i32 = NXT_WASM_MEM_SIZE + NXT_WASM_PAGE_SIZE; ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func, 1, results, i, args); if (!ok) { return -1; } ctx->baddr_off = results[0].of.i32; ctx->baddr = wasm_runtime_addr_app_to_native(rt_ctx->module_inst, ctx->baddr_off); return 0; } static int nxt_wamr_init(nxt_wasm_ctx_t *ctx) { int err; bool ok; char error_buf[128]; FILE *fp; size_t file_size; uint32_t stack_size = 16384, heap_size = 16384; nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; ok = wasm_runtime_init(); if (!ok) { nxt_wamr_err_msg("wasm_runtime_init() failed"); return -1; } ok = nxt_wamr_set_function_imports(); if (!ok) { nxt_wamr_err_msg("nxt_wamr_set_function_imports() failed"); return -1; } fp = fopen(ctx->module_path, "r"); if (!fp) { nxt_wamr_err_msg("fopen(\"%s\") failed", ctx->module_path); return -1; } fseek(fp, 0L, SEEK_END); file_size = ftell(fp); rt_ctx->mod_buf = malloc(file_size); fseek(fp, 0L, SEEK_SET); if (fread(rt_ctx->mod_buf, file_size, 1, fp) != 1) { nxt_wamr_err_msg("fread(\"%s\") failed", ctx->module_path); return -1; } fclose(fp); rt_ctx->module = wasm_runtime_load(rt_ctx->mod_buf, file_size, error_buf, sizeof(error_buf)); if (rt_ctx->module == NULL) { nxt_wamr_err_msg("wasm_runtime_load() failed"); return -1; } nxt_wamr_wasi_init(ctx); rt_ctx->module_inst = wasm_runtime_instantiate(rt_ctx->module, stack_size, heap_size, error_buf, sizeof(error_buf)); if (rt_ctx->module_inst == NULL) { nxt_wamr_err_msg("wasm_runtime_instantiate() failed"); return -1; } rt_ctx->exec_env = wasm_runtime_create_exec_env(rt_ctx->module_inst, stack_size); if (rt_ctx->exec_env == NULL) { nxt_wamr_err_msg("wasm_runtime_create_exec_env() failed"); return -1; } wasm_runtime_set_user_data(rt_ctx->exec_env, ctx); err = nxt_wamr_get_function_exports(ctx); if (err) { nxt_wamr_err_msg("nxt_wamr_get_function_exports() failed"); return -1; } err = nxt_wamr_init_memory(ctx); if (err) { nxt_wamr_err_msg("nxt_wamr_init_memory() failed"); return -1; } return 0; } static void nxt_wamr_destroy(const nxt_wasm_ctx_t *ctx) { uint32_t i = 0; wasm_val_t args[1] = { }; nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx; const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_FREE].func; args[i].kind = WASM_I32; args[i++].of.i32 = ctx->baddr_off; wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func, 0, NULL, i, args); wasm_runtime_destroy_exec_env(rt_ctx->exec_env); wasm_runtime_deinstantiate(rt_ctx->module_inst); wasm_runtime_unload(rt_ctx->module); free(rt_ctx->mod_buf); wasm_runtime_destroy(); } const nxt_wasm_operations_t nxt_wasm_ops = { .init = nxt_wamr_init, .destroy = nxt_wamr_destroy, .exec_request = nxt_wamr_execute_request, .exec_hook = nxt_wamr_execute_hook, };