From 4adb2e1311504cadafc07fd9b0935c6e00cdcd18 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 6 Dec 2021 20:14:30 +0800 Subject: [PATCH 1/5] Merge main into dev/socket_api (#871) --- README.md | 1 + build-scripts/config_common.cmake | 10 +- core/iwasm/aot/aot_intrinsic.c | 3 +- core/iwasm/aot/aot_loader.c | 10 +- core/iwasm/aot/aot_reloc.h | 1 + core/iwasm/aot/aot_runtime.c | 2 +- core/iwasm/common/wasm_exec_env.c | 4 - core/iwasm/common/wasm_runtime_common.c | 80 ++++++++- core/iwasm/common/wasm_runtime_common.h | 10 ++ core/iwasm/common/wasm_shared_memory.c | 3 +- core/iwasm/compilation/aot_compiler.c | 54 ++++++ core/iwasm/compilation/aot_emit_aot_file.c | 10 +- core/iwasm/compilation/aot_emit_memory.c | 134 ++++++++++++-- core/iwasm/compilation/aot_llvm.h | 3 + core/iwasm/compilation/aot_llvm_extra.cpp | 115 ++++++++++++ core/iwasm/compilation/iwasm_compl.cmake | 8 + core/iwasm/include/wasm_export.h | 31 ++++ core/iwasm/interpreter/wasm.h | 14 ++ core/iwasm/interpreter/wasm_loader.c | 25 ++- core/iwasm/interpreter/wasm_mini_loader.c | 30 ++-- core/iwasm/interpreter/wasm_runtime.c | 53 +++++- core/iwasm/interpreter/wasm_runtime.h | 3 +- .../libraries/debug-engine/debug_engine.c | 170 +++++++++++------- .../libraries/debug-engine/debug_engine.h | 5 + core/iwasm/libraries/debug-engine/gdbserver.c | 49 +++-- core/iwasm/libraries/debug-engine/gdbserver.h | 5 +- core/iwasm/libraries/debug-engine/handler.c | 56 ++++-- .../lib-pthread/lib_pthread_wrapper.c | 2 +- .../libraries/thread-mgr/thread_manager.c | 64 ++++--- .../libraries/thread-mgr/thread_manager.h | 8 + doc/build_wamr.md | 4 + doc/source_debugging.md | 48 +++++ doc/xip.md | 14 ++ .../enclave-sample/Enclave/Enclave.cpp | 56 ++++-- product-mini/platforms/posix/main.c | 16 +- .../wamr-test-suites/spec-test-script/all.py | 20 +++ .../spec-test-script/runtest.py | 7 + tests/wamr-test-suites/test_wamr.sh | 18 +- 38 files changed, 940 insertions(+), 206 deletions(-) create mode 100644 doc/xip.md diff --git a/README.md b/README.md index bd9418daaf..8ac6735189 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ iwasm VM core - [Thread management and pthread library](./doc/pthread_library.md), ref to [sample](samples/multi-thread) - [Linux SGX (Intel Software Guard Extension) support](./doc/linux_sgx.md) - [Source debugging](./doc/source_debugging.md) +- [XIP (Execution In Place) support](./doc/xip.md) ### post-MVP features - [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 3d94acf540..02ae865cd7 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -61,9 +61,13 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8) set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") endif () else () - add_definitions (-m32) - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") - set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") + include(CheckCCompilerFlag) + Check_C_Compiler_Flag(-m32 M32_OK) + if (M32_OK OR WAMR_BUILD_TARGET STREQUAL "X86_32") + add_definitions (-m32) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") + endif () endif () endif () diff --git a/core/iwasm/aot/aot_intrinsic.c b/core/iwasm/aot/aot_intrinsic.c index ba02dca0ba..2b4a350b9a 100644 --- a/core/iwasm/aot/aot_intrinsic.c +++ b/core/iwasm/aot/aot_intrinsic.c @@ -53,7 +53,8 @@ static const aot_intrinsic g_intrinsic_mapping[] = { { "f64_convert_i64_u", "aot_intrinsic_u64_to_f64", AOT_INTRINSIC_FLAG_U64_TO_F64 }, { "f32_convert_i64_s", "aot_intrinsic_i64_to_f32", AOT_INTRINSIC_FLAG_I64_TO_F32 }, { "f32_convert_i64_u", "aot_intrinsic_u64_to_f32", AOT_INTRINSIC_FLAG_U64_TO_F32 }, - { "i32_trunc_f64_u", "aot_intrinsic_f64_to_u32", AOT_INTRINSIC_FLAG_I32_TO_F64 }, + { "i32_trunc_f64_u", "aot_intrinsic_f64_to_u32", AOT_INTRINSIC_FLAG_F64_TO_U32 }, + { "i32_trunc_f64_s", "aot_intrinsic_f64_to_i32", AOT_INTRINSIC_FLAG_F64_TO_I32 }, { "f32_demote_f64", "aot_intrinsic_f64_to_f32", AOT_INTRINSIC_FLAG_F64_TO_F32 }, { "f64_promote_f32", "aot_intrinsic_f32_to_f64", AOT_INTRINSIC_FLAG_F32_TO_F64 }, { "f32_cmp", "aot_intrinsic_f32_cmp", AOT_INTRINSIC_FLAG_F32_CMP }, diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index c3c4072c6c..7631be23ff 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -90,7 +90,7 @@ static bool check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length, char *error_buf, uint32 error_buf_size) { - if (buf + length > buf_end) { + if (buf + length < buf || buf + length > buf_end) { set_error_buf(error_buf, error_buf_size, "unexpect end"); return false; } @@ -166,6 +166,7 @@ GET_U64_FROM_ADDR(uint32 *addr) #define BIN_TYPE_ELF32B 1 /* 32-bit big endian */ #define BIN_TYPE_ELF64L 2 /* 64-bit little endian */ #define BIN_TYPE_ELF64B 3 /* 64-bit big endian */ +#define BIN_TYPE_COFF32 4 /* 32-bit little endian */ #define BIN_TYPE_COFF64 6 /* 64-bit little endian */ /* Legal values for e_type (object file type). */ @@ -188,7 +189,8 @@ GET_U64_FROM_ADDR(uint32 *addr) #define E_MACHINE_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */ #define E_MACHINE_XTENSA 94 /* Tensilica Xtensa Architecture */ #define E_MACHINE_RISCV 243 /* RISC-V 32/64 */ -#define E_MACHINE_WIN_X86_64 0x8664 /* Windowx x86-64 architecture */ +#define E_MACHINE_WIN_I386 0x14c /* Windows i386 architecture */ +#define E_MACHINE_WIN_X86_64 0x8664 /* Windows x86-64 architecture */ /* Legal values for e_version */ #define E_VERSION_CURRENT 1 /* Current version */ @@ -317,6 +319,7 @@ get_aot_file_target(AOTTargetInfo *target_info, char *target_buf, machine_type = "x86_64"; break; case E_MACHINE_386: + case E_MACHINE_WIN_I386: machine_type = "i386"; break; case E_MACHINE_ARM: @@ -2187,6 +2190,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, || !strcmp(group->section_name, ".text") #endif ) { +#if !defined(BH_PLATFORM_LINUX) && !defined(BH_PLATFORM_LINUX_SGX) \ + && !defined(BH_PLATFORM_DARWIN) if (module->native_symbol_count > 0) { set_error_buf(error_buf, error_buf_size, "cannot apply relocation to text section " @@ -2194,6 +2199,7 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, "\"--enable-indirect-mode\" flag"); goto fail; } +#endif if (!do_text_relocation(module, group, error_buf, error_buf_size)) goto fail; } diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index bbcac8cbfe..65fccedeb6 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -99,6 +99,7 @@ typedef struct { REG_SYM(aot_intrinsic_i64_to_f64), \ REG_SYM(aot_intrinsic_u64_to_f64), \ REG_SYM(aot_intrinsic_f64_to_f32), \ + REG_SYM(aot_intrinsic_f64_to_i32), \ REG_SYM(aot_intrinsic_f64_to_u32), \ REG_SYM(aot_intrinsic_f32_to_f64), \ REG_SYM(aot_intrinsic_f32_cmp), \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index b97e952832..c769a527e1 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1774,7 +1774,7 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, aot_set_exception(module_inst, "app heap corrupted"); } else { - aot_set_exception(module_inst, "out of memory"); + LOG_WARNING("warning: allocate %u bytes memory failed", size); } return 0; } diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 685542b793..6a3af642d0 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -148,9 +148,6 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, wasm_exec_env_destroy_internal(exec_env); return NULL; } -#if WASM_ENABLE_DEBUG_INTERP != 0 - wasm_debug_instance_create(cluster); -#endif #endif /* end of WASM_ENABLE_THREAD_MGR */ return exec_env; @@ -165,7 +162,6 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env) if (cluster) { #if WASM_ENABLE_DEBUG_INTERP != 0 wasm_cluster_thread_exited(exec_env); - wasm_debug_instance_destroy(cluster); #endif wasm_cluster_terminate_all_except_self(cluster, exec_env); wasm_cluster_del_exec_env(cluster, exec_env); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 5187d1224d..075e422c97 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -294,6 +294,84 @@ get_package_type(const uint8 *buf, uint32 size) return Package_Type_Unknown; } +#if WASM_ENABLE_AOT != 0 +static uint8 * +align_ptr(const uint8 *p, uint32 b) +{ + uintptr_t v = (uintptr_t)p; + uintptr_t m = b - 1; + return (uint8 *)((v + m) & ~m); +} + +#define CHECK_BUF(buf, buf_end, length) \ + do { \ + if (buf + length < buf || buf + length > buf_end) \ + return false; \ + } while (0) + +#define read_uint32(p, p_end, res) \ + do { \ + p = (uint8 *)align_ptr(p, sizeof(uint32)); \ + CHECK_BUF(p, p_end, sizeof(uint32)); \ + res = *(uint32 *)p; \ + p += sizeof(uint32); \ + } while (0) + +bool +wasm_runtime_is_xip_file(const uint8 *buf, uint32 size) +{ + const uint8 *p = buf, *p_end = buf + size; + uint32 section_type, sub_section_type, section_size; + + if (get_package_type(buf, size) != Wasm_Module_AoT) + return false; + + CHECK_BUF(p, p_end, 8); + p += 8; + while (p < p_end) { + read_uint32(p, p_end, section_type); + read_uint32(p, p_end, section_size); + CHECK_BUF(p, p_end, section_size); + + if (section_type == AOT_SECTION_TYPE_CUSTOM) { + read_uint32(p, p_end, sub_section_type); + if (sub_section_type == AOT_CUSTOM_SECTION_NATIVE_SYMBOL) { + return true; + } + else { + p -= sizeof(uint32); + } + } + else if (section_type >= AOT_SECTION_TYPE_SIGANATURE) { + return false; + } + p += section_size; + } + + return false; +} +#endif /* end of WASM_ENABLE_AOT */ + +#if (WASM_ENABLE_THREAD_MGR != 0) && (WASM_ENABLE_DEBUG_INTERP != 0) +uint32 +wasm_runtime_start_debug_instance(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + if (cluster->debug_inst) { + LOG_WARNING("Cluster already bind to a debug instance"); + return cluster->debug_inst->control_thread->port; + } + + if (wasm_debug_instance_create(cluster)) { + return cluster->debug_inst->control_thread->port; + } + + return 0; +} +#endif + #if WASM_ENABLE_MULTI_MODULE != 0 static module_reader reader; static module_destroyer destroyer; @@ -1431,7 +1509,7 @@ wasm_runtime_create_exec_env_and_call_wasm( if (module_inst->module_type == Wasm_Module_Bytecode) ret = wasm_create_exec_env_and_call_function( (WASMModuleInstance *)module_inst, (WASMFunctionInstance *)function, - argc, argv); + argc, argv, true); #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 483bf9443b..29eadb62fa 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -406,6 +406,10 @@ wasm_runtime_destroy(void); WASM_RUNTIME_API_EXTERN PackageType get_package_type(const uint8 *buf, uint32 size); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_xip_file(const uint8 *buf, uint32 size); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN WASMModuleCommon * wasm_runtime_load(const uint8 *buf, uint32 size, char *error_buf, @@ -494,6 +498,12 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, uint32 num_results, wasm_val_t *results, uint32 num_args, ...); +#if WASM_ENABLE_DEBUG_INTERP != 0 +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32 +wasm_runtime_start_debug_instance(WASMExecEnv *exec_env); +#endif + /** * Call a function reference of a given WASM runtime instance with * arguments. diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 65c98d4ef3..6fc9bf2073 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -224,7 +224,8 @@ acquire_wait_info(void *address, bool create) AtomicWaitInfo *wait_info = NULL; bh_list_status ret; - wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address); + if (address) + wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address); if (!create) return wait_info; diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index aa4f24c334..0eacfa6408 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2538,6 +2538,39 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) return false; } +/* Check whether the target supports hardware atomic instructions */ +static bool +aot_require_lower_atomic_pass(AOTCompContext *comp_ctx) +{ + bool ret = false; + if (!strncmp(comp_ctx->target_arch, "riscv", 5)) { + char *feature = + LLVMGetTargetMachineFeatureString(comp_ctx->target_machine); + + if (feature) { + if (!strstr(feature, "+a")) { + ret = true; + } + LLVMDisposeMessage(feature); + } + } + return ret; +} + +/* Check whether the target needs to expand switch to if/else */ +static bool +aot_require_lower_switch_pass(AOTCompContext *comp_ctx) +{ + bool ret = false; + + /* IR switch/case will cause .rodata relocation on riscv */ + if (!strncmp(comp_ctx->target_arch, "riscv", 5)) { + ret = true; + } + + return ret; +} + bool aot_compile_wasm(AOTCompContext *comp_ctx) { @@ -2625,6 +2658,27 @@ aot_compile_wasm(AOTCompContext *comp_ctx) LLVMPassManagerBuilderDispose(pass_mgr_builder); } + if (comp_ctx->optimize && comp_ctx->is_indirect_mode) { + LLVMPassManagerRef common_pass_mgr = NULL; + + if (!(common_pass_mgr = LLVMCreatePassManager())) { + aot_set_last_error("create pass manager failed"); + return false; + } + + aot_add_expand_memory_op_pass(common_pass_mgr); + + if (aot_require_lower_atomic_pass(comp_ctx)) + LLVMAddLowerAtomicPass(common_pass_mgr); + + if (aot_require_lower_switch_pass(comp_ctx)) + LLVMAddLowerSwitchPass(common_pass_mgr); + + LLVMRunPassManager(common_pass_mgr, comp_ctx->module); + + LLVMDisposePassManager(common_pass_mgr); + } + return true; } diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 26e94af592..aac8fee954 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -1913,7 +1913,8 @@ struct coff_hdr { #define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_MACHINE_IA64 0x0200 -#define AOT_COFF_BIN_TYPE 6 +#define AOT_COFF32_BIN_TYPE 4 /* 32-bit little endian */ +#define AOT_COFF64_BIN_TYPE 6 /* 64-bit little endian */ #define EI_NIDENT 16 @@ -2029,8 +2030,11 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data) obj_data->target_info.e_version = 1; obj_data->target_info.e_flags = 0; - if (coff_header->u16Machine == IMAGE_FILE_MACHINE_AMD64) - obj_data->target_info.bin_type = AOT_COFF_BIN_TYPE; + if (coff_header->u16Machine == IMAGE_FILE_MACHINE_AMD64 + || coff_header->u16Machine == IMAGE_FILE_MACHINE_IA64) + obj_data->target_info.bin_type = AOT_COFF64_BIN_TYPE; + else if (coff_header->u16Machine == IMAGE_FILE_MACHINE_I386) + obj_data->target_info.bin_type = AOT_COFF32_BIN_TYPE; } else if (bin_type == LLVMBinaryTypeELF32L || bin_type == LLVMBinaryTypeELF32B) { diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 86ddb3c6f7..c089f426e2 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -6,6 +6,7 @@ #include "aot_emit_memory.h" #include "aot_emit_exception.h" #include "../aot/aot_runtime.h" +#include "aot_intrinsic.h" #define BUILD_ICMP(op, left, right, res, name) \ do { \ @@ -951,13 +952,66 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) if (!(dst_addr = check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len))) return false; - /* TODO: lookup func ptr of "memmove" to call for XIP mode */ + if (comp_ctx->is_indirect_mode) { + LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; + LLVMValueRef func, params[3]; + int32 func_idx; - if (!(res = LLVMBuildMemMove(comp_ctx->builder, dst_addr, 1, src_addr, 1, - len))) { - aot_set_last_error("llvm build memmove failed."); - return false; + if (!(dst_addr = + LLVMBuildBitCast(comp_ctx->builder, dst_addr, INT32_PTR_TYPE, + "memmove dst addr cast type"))) { + aot_set_last_error("llvm cast memmove dst addr type failed."); + return false; + } + + if (!(src_addr = + LLVMBuildBitCast(comp_ctx->builder, src_addr, INT32_PTR_TYPE, + "memmove src addr cast type"))) { + aot_set_last_error("llvm cast memmove src addr type failed."); + return false; + } + + param_types[0] = INT32_PTR_TYPE; + param_types[1] = INT32_PTR_TYPE; + param_types[2] = I32_TYPE; + ret_type = INT32_PTR_TYPE; + + if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false))) { + aot_set_last_error("create LLVM function type failed."); + return false; + } + + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function pointer type failed."); + return false; + } + + func_idx = aot_get_native_symbol_index(comp_ctx, "memmove"); + if (func_idx < 0) { + return false; + } + if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, + func_ptr_type, func_idx))) { + return false; + } + + params[0] = dst_addr; + params[1] = src_addr; + params[2] = len; + if (!(res = LLVMBuildCall(comp_ctx->builder, func, params, 3, + "call memmove"))) { + aot_set_last_error("llvm build memmove failed."); + return false; + } } + else { + if (!(res = LLVMBuildMemMove(comp_ctx->builder, dst_addr, 1, src_addr, + 1, len))) { + aot_set_last_error("llvm build memmove failed."); + return false; + } + } + return true; fail: return false; @@ -981,11 +1035,57 @@ aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) return false; } - /* TODO: lookup func ptr of "memset" to call for XIP mode */ + if (comp_ctx->is_indirect_mode) { + LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; + LLVMValueRef func, params[3]; + int32 func_idx; - if (!(res = LLVMBuildMemSet(comp_ctx->builder, dst_addr, val, len, 1))) { - aot_set_last_error("llvm build memset failed."); - return false; + if (!(dst_addr = + LLVMBuildBitCast(comp_ctx->builder, dst_addr, INT32_PTR_TYPE, + "memset dst addr cast type"))) { + aot_set_last_error("llvm cast memset dst addr type failed."); + return false; + } + + param_types[0] = INT32_PTR_TYPE; + param_types[1] = INT8_TYPE; + param_types[2] = I32_TYPE; + ret_type = INT32_PTR_TYPE; + + if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false))) { + aot_set_last_error("create LLVM function type failed."); + return false; + } + + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function pointer type failed."); + return false; + } + + func_idx = aot_get_native_symbol_index(comp_ctx, "memset"); + if (func_idx < 0) { + return false; + } + if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, + func_ptr_type, func_idx))) { + return false; + } + + params[0] = dst_addr; + params[1] = val; + params[2] = len; + if (!(res = LLVMBuildCall(comp_ctx->builder, func, params, 3, + "call memset"))) { + aot_set_last_error("llvm build memset failed."); + return false; + } + } + else { + if (!(res = + LLVMBuildMemSet(comp_ctx->builder, dst_addr, val, len, 1))) { + aot_set_last_error("llvm build memset failed."); + return false; + } } return true; fail: @@ -1127,16 +1227,20 @@ aot_compile_op_atomic_cmpxchg(AOTCompContext *comp_ctx, } if (op_type == VALUE_TYPE_I32) { - if (!(result = LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE, - "result_i32"))) { - goto fail; + if (LLVMTypeOf(result) != I32_TYPE) { + if (!(result = LLVMBuildZExt(comp_ctx->builder, result, I32_TYPE, + "result_i32"))) { + goto fail; + } } PUSH_I32(result); } else { - if (!(result = LLVMBuildZExt(comp_ctx->builder, result, I64_TYPE, - "result_i64"))) { - goto fail; + if (LLVMTypeOf(result) != I64_TYPE) { + if (!(result = LLVMBuildZExt(comp_ctx->builder, result, I64_TYPE, + "result_i64"))) { + goto fail; + } } PUSH_I64(result); } diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index ebd1703393..dd29cae347 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -445,6 +445,9 @@ aot_get_func_from_table(const AOTCompContext *comp_ctx, LLVMValueRef base, bool aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); +void +aot_add_expand_memory_op_pass(LLVMPassManagerRef pass); + #if WASM_ENABLE_LAZY_JIT != 0 void aot_handle_llvm_errmsg(char *error_buf, uint32 error_buf_size, diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index 5ca2a6173d..c6a059c60a 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -6,20 +6,29 @@ #include #include #include +#include +#include #include #include #include #include #include #include +#include #include #include #include #include #include +#include +#include +#include +#include #include #include +#include #include +#include #include using namespace llvm; @@ -33,6 +42,9 @@ WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, extern "C" bool aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); +extern "C" void +aot_add_expand_memory_op_pass(LLVMPassManagerRef pass); + extern "C" void aot_func_disable_tce(LLVMValueRef func); @@ -106,6 +118,109 @@ WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, return 1; } +class ExpandMemoryOpPass : public llvm::ModulePass +{ + public: + static char ID; + + ExpandMemoryOpPass() + : ModulePass(ID) + {} + + bool runOnModule(Module &M) override; + + bool expandMemIntrinsicUses(Function &F); + StringRef getPassName() const override + { + return "Expand memory operation intrinsics"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override + { + AU.addRequired(); + } +}; + +char ExpandMemoryOpPass::ID = 0; + +bool +ExpandMemoryOpPass::expandMemIntrinsicUses(Function &F) +{ + Intrinsic::ID ID = F.getIntrinsicID(); + bool Changed = false; + + for (auto I = F.user_begin(), E = F.user_end(); I != E;) { + Instruction *Inst = cast(*I); + ++I; + + switch (ID) { + case Intrinsic::memcpy: + { + auto *Memcpy = cast(Inst); + Function *ParentFunc = Memcpy->getParent()->getParent(); + const TargetTransformInfo &TTI = + getAnalysis().getTTI( + *ParentFunc); + expandMemCpyAsLoop(Memcpy, TTI); + Changed = true; + Memcpy->eraseFromParent(); + break; + } + case Intrinsic::memmove: + { + auto *Memmove = cast(Inst); + expandMemMoveAsLoop(Memmove); + Changed = true; + Memmove->eraseFromParent(); + break; + } + case Intrinsic::memset: + { + auto *Memset = cast(Inst); + expandMemSetAsLoop(Memset); + Changed = true; + Memset->eraseFromParent(); + break; + } + default: + break; + } + } + + return Changed; +} + +bool +ExpandMemoryOpPass::runOnModule(Module &M) +{ + bool Changed = false; + + for (Function &F : M) { + if (!F.isDeclaration()) + continue; + + switch (F.getIntrinsicID()) { + case Intrinsic::memcpy: + case Intrinsic::memmove: + case Intrinsic::memset: + if (expandMemIntrinsicUses(F)) + Changed = true; + break; + + default: + break; + } + } + + return Changed; +} + +void +aot_add_expand_memory_op_pass(LLVMPassManagerRef pass) +{ + unwrap(pass)->add(new ExpandMemoryOpPass()); +} + bool aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str) { diff --git a/core/iwasm/compilation/iwasm_compl.cmake b/core/iwasm/compilation/iwasm_compl.cmake index 59455de9a3..4ec4603049 100644 --- a/core/iwasm/compilation/iwasm_compl.cmake +++ b/core/iwasm/compilation/iwasm_compl.cmake @@ -16,3 +16,11 @@ endif() set (IWASM_COMPL_SOURCE ${source_all}) +# Disalbe rtti to works with LLVM + +if (MSVC) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-") +else() + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +endif() + diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 9b33f9f4c7..8ad85a3d2b 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -235,6 +235,17 @@ wasm_runtime_free(void *ptr); WASM_RUNTIME_API_EXTERN package_type_t get_package_type(const uint8_t *buf, uint32_t size); +/** + * Check whether a file is an AOT XIP (Execution In Place) file + * + * @param buf the package buffer + * @param size the package buffer size + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_xip_file(const uint8_t *buf, uint32_t size); + /** * It is a callback for WAMR providing by embedding to load a module file * into a buffer @@ -408,6 +419,26 @@ wasm_runtime_create_exec_env(wasm_module_inst_t module_inst, WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env); +/** + * Start debug instance based on given execution environment. + * Note: + * The debug instance will be destroyed during destroying the + * execution environment, developers don't need to destroy it + * manually. + * If the cluster of this execution environment has already + * been bound to a debug instance, this function will return true + * directly. + * If developer spawns some exec_env by wasm_runtime_spawn_exec_env, + * don't need to call this function for every spawned exec_env as + * they are sharing the same cluster with the main exec_env. + * + * @param exec_env the execution environment to start debug instance + * + * @return debug port if success, 0 otherwise. + */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env); + /** * Initialize thread environment. * Note: diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index f3e3e5b6f5..bda5b3467d 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -419,6 +419,20 @@ struct WASMModule { uint64 buf_code_size; #endif +#if WASM_ENABLE_DEBUG_INTERP != 0 + /** + * Count how many instances reference this module. When source + * debugging feature enabled, the debugger may modify the code + * section of the module, so we need to report a warning if user + * create several instances based on the same module + * + * Sub_instances created by lib-pthread or spawn API will not + * influence or check the ref count + */ + uint32 ref_count; + korp_mutex ref_count_lock; +#endif + #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 const uint8 *name_section_buf; const uint8 *name_section_buf_end; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index d3fbd47a29..e3f0649ec5 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -47,7 +47,7 @@ static bool check_buf(const uint8 *buf, const uint8 *buf_end, uint32 length, char *error_buf, uint32 error_buf_size) { - if (buf + length > buf_end) { + if (buf + length < buf || buf + length > buf_end) { set_error_buf(error_buf, error_buf_size, "unexpected end of section or function"); return false; @@ -59,7 +59,7 @@ static bool check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, char *error_buf, uint32 error_buf_size) { - if (buf + length > buf_end) { + if (buf + length < buf || buf + length > buf_end) { set_error_buf(error_buf, error_buf_size, "unexpected end"); return false; } @@ -1034,7 +1034,6 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end, bool linked_call_conv_raw = false; bool is_native_symbol = false; - CHECK_BUF(p, p_end, 1); read_leb_uint32(p, p_end, declare_type_index); *p_buf = p; @@ -3041,6 +3040,18 @@ load_from_sections(WASMModule *module, WASMSection *sections, break; } } + if (!aux_stack_top_global) { + /* Auxiliary stack global isn't found, it must be unused + in the wasm app, as if it is used, the global must be + defined. Here we set it to __heap_base global and set + its size to 0. */ + aux_stack_top_global = aux_heap_base_global; + aux_stack_top = aux_heap_base; + module->aux_stack_top_global_index = + module->aux_heap_base_global_index; + module->aux_stack_bottom = aux_stack_top; + module->aux_stack_size = 0; + } break; } } @@ -3085,7 +3096,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, export->name, export->index); /* resolve retain function. - If not find, reset malloc function index */ + If not found, reset malloc function index */ export_tmp = module->exports; for (j = 0; j < module->export_count; j++, export_tmp++) { if ((export_tmp->kind == EXPORT_KIND_FUNC) @@ -3226,6 +3237,10 @@ create_module(char *error_buf, uint32 error_buf_size) #endif #if WASM_ENABLE_DEBUG_INTERP != 0 bh_list_init(&module->fast_opcode_list); + if (os_mutex_init(&module->ref_count_lock) != 0) { + wasm_runtime_free(module); + return NULL; + } #endif return module; } @@ -3335,7 +3350,6 @@ create_sections(const uint8 *buf, uint32 size, WASMSection **p_section_list, } last_section_index = section_index; } - CHECK_BUF1(p, p_end, 1); read_leb_uint32(p, p_end, section_size); CHECK_BUF1(p, p_end, section_size); @@ -3558,6 +3572,7 @@ wasm_loader_unload(WASMModule *module) wasm_runtime_free(fast_opcode); fast_opcode = next; } + os_mutex_destroy(&module->ref_count_lock); #endif wasm_runtime_free(module); } diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 10035f93fa..4a43b068f5 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -25,14 +25,14 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) string); } -#define CHECK_BUF(buf, buf_end, length) \ - do { \ - bh_assert(buf + length <= buf_end); \ +#define CHECK_BUF(buf, buf_end, length) \ + do { \ + bh_assert(buf + length >= buf && buf + length <= buf_end); \ } while (0) -#define CHECK_BUF1(buf, buf_end, length) \ - do { \ - bh_assert(buf + length <= buf_end); \ +#define CHECK_BUF1(buf, buf_end, length) \ + do { \ + bh_assert(buf + length >= buf && buf + length <= buf_end); \ } while (0) #define skip_leb(p) while (*p++ & 0x80) @@ -45,7 +45,7 @@ is_32bit_type(uint8 type) { if (type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32 #if WASM_ENABLE_REF_TYPES != 0 - || type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF) + || type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF #endif ) return true; @@ -412,7 +412,6 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end, void *linked_attachment = NULL; bool linked_call_conv_raw = false; - CHECK_BUF(p, p_end, 1); read_leb_uint32(p, p_end, declare_type_index); *p_buf = p; @@ -1960,6 +1959,18 @@ load_from_sections(WASMModule *module, WASMSection *sections, break; } } + if (!aux_stack_top_global) { + /* Auxiliary stack global isn't found, it must be unused + in the wasm app, as if it is used, the global must be + defined. Here we set it to __heap_base global and set + its size to 0. */ + aux_stack_top_global = aux_heap_base_global; + aux_stack_top = aux_heap_base; + module->aux_stack_top_global_index = + module->aux_heap_base_global_index; + module->aux_stack_bottom = aux_stack_top; + module->aux_stack_size = 0; + } break; } } @@ -2003,7 +2014,7 @@ load_from_sections(WASMModule *module, WASMSection *sections, export->name, export->index); /* resolve retain function. - If not find, reset malloc function index */ + If not found, reset malloc function index */ export_tmp = module->exports; for (j = 0; j < module->export_count; j++, export_tmp++) { if ((export_tmp->kind == EXPORT_KIND_FUNC) @@ -2232,7 +2243,6 @@ create_sections(const uint8 *buf, uint32 size, WASMSection **p_section_list, || last_section_index < section_index); last_section_index = section_index; } - CHECK_BUF1(p, p_end, 1); read_leb_uint32(p, p_end, section_size); CHECK_BUF1(p, p_end, section_size); diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 14a4286490..f12c9ebf75 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -900,7 +900,7 @@ execute_post_inst_function(WASMModuleInstance *module_inst) return true; return wasm_create_exec_env_and_call_function(module_inst, post_inst_func, - 0, NULL); + 0, NULL, false); } #if WASM_ENABLE_BULK_MEMORY != 0 @@ -929,7 +929,7 @@ execute_memory_init_function(WASMModuleInstance *module_inst) return true; return wasm_create_exec_env_and_call_function(module_inst, memory_init_func, - 0, NULL); + 0, NULL, false); } #endif @@ -944,7 +944,8 @@ execute_start_function(WASMModuleInstance *module_inst) bh_assert(!func->is_import_func && func->param_cell_num == 0 && func->ret_cell_num == 0); - return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL); + return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL, + false); } static bool @@ -972,11 +973,11 @@ execute_malloc_function(WASMModuleInstance *module_inst, } ret = wasm_create_exec_env_and_call_function(module_inst, malloc_func, argc, - argv); + argv, false); if (retain_func && ret) { ret = wasm_create_exec_env_and_call_function(module_inst, retain_func, - 1, argv); + 1, argv, false); } if (ret) @@ -992,7 +993,7 @@ execute_free_function(WASMModuleInstance *module_inst, argv[0] = offset; return wasm_create_exec_env_and_call_function(module_inst, free_func, 1, - argv); + argv, false); } #if WASM_ENABLE_MULTI_MODULE != 0 @@ -1125,6 +1126,19 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, if (!module) return NULL; +#if WASM_ENABLE_DEBUG_INTERP != 0 + if (!is_sub_inst) { + os_mutex_lock(&module->ref_count_lock); + if (module->ref_count != 0) { + LOG_WARNING( + "warning: multiple instances referencing the same module may " + "cause unexpected behaviour during debugging"); + } + module->ref_count++; + os_mutex_unlock(&module->ref_count_lock); + } +#endif + /* Check heap size */ heap_size = align_uint(heap_size, 8); if (heap_size > APP_HEAP_SIZE_MAX) @@ -1133,6 +1147,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, /* Allocate the memory */ if (!(module_inst = runtime_malloc(sizeof(WASMModuleInstance), error_buf, error_buf_size))) { +#if WASM_ENABLE_DEBUG_INTERP != 0 + if (!is_sub_inst) { + os_mutex_lock(&module->ref_count_lock); + module->ref_count--; + os_mutex_unlock(&module->ref_count_lock); + } +#endif return NULL; } @@ -1519,7 +1540,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, (WASMModuleInstanceCommon *)module_inst); #endif (void)global_data_end; + return module_inst; + fail: wasm_deinstantiate(module_inst, false); return NULL; @@ -1576,6 +1599,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) } #endif +#if WASM_ENABLE_DEBUG_INTERP != 0 + if (!is_sub_inst) { + os_mutex_lock(&module_inst->module->ref_count_lock); + module_inst->module->ref_count--; + os_mutex_unlock(&module_inst->module->ref_count_lock); + } +#endif + wasm_runtime_free(module_inst); } @@ -1661,7 +1692,8 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function, bool wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, WASMFunctionInstance *func, - unsigned argc, uint32 argv[]) + unsigned argc, uint32 argv[], + bool enable_debug) { WASMExecEnv *exec_env; bool ret; @@ -1680,6 +1712,11 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, } #if WASM_ENABLE_THREAD_MGR != 0 + if (enable_debug) { +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_runtime_start_debug_instance(exec_env); +#endif + } } #endif @@ -1830,7 +1867,7 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, wasm_set_exception(module_inst, "app heap corrupted"); } else { - wasm_set_exception(module_inst, "out of memory"); + LOG_WARNING("warning: allocate %u bytes memory failed", size); } return 0; } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 56871b3652..27d63068e4 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -320,7 +320,8 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function, bool wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, WASMFunctionInstance *function, - unsigned argc, uint32 argv[]); + unsigned argc, uint32 argv[], + bool enable_debug); bool wasm_create_exec_env_singleton(WASMModuleInstance *module_inst); diff --git a/core/iwasm/libraries/debug-engine/debug_engine.c b/core/iwasm/libraries/debug-engine/debug_engine.c index d7b73298d2..0920ec5220 100644 --- a/core/iwasm/libraries/debug-engine/debug_engine.c +++ b/core/iwasm/libraries/debug-engine/debug_engine.c @@ -7,7 +7,7 @@ #include "bh_log.h" #include "gdbserver.h" -#include "platform_api_extension.h" +#include "bh_platform.h" #include "wasm_interp.h" #include "wasm_opcode.h" #include "wasm_runtime.h" @@ -54,20 +54,11 @@ control_thread_routine(void *arg) { WASMDebugInstance *debug_inst = (WASMDebugInstance *)arg; WASMDebugControlThread *control_thread = NULL; - WASMCluster *cluster = NULL; - WASMExecEnv *exec_env; - bh_assert(debug_inst); control_thread = debug_inst->control_thread; bh_assert(control_thread); - cluster = debug_inst->cluster; - bh_assert(cluster); - - exec_env = bh_list_first_elem(&cluster->exec_env_list); - bh_assert(exec_env); - - os_mutex_lock(&exec_env->wait_lock); + os_mutex_lock(&debug_inst->wait_lock); control_thread->status = RUNNING; @@ -84,19 +75,31 @@ control_thread_routine(void *arg) LOG_WARNING("control thread of debug object %p start\n", debug_inst); control_thread->server = - wasm_launch_gdbserver(control_thread->ip_addr, control_thread->port); + wasm_create_gdbserver(control_thread->ip_addr, &control_thread->port); + if (!control_thread->server) { LOG_ERROR("Failed to create debug server\n"); - os_cond_signal(&exec_env->wait_cond); - os_mutex_unlock(&exec_env->wait_lock); + os_cond_signal(&debug_inst->wait_cond); + os_mutex_unlock(&debug_inst->wait_lock); return NULL; } control_thread->server->thread = control_thread; - /* control thread ready, notify main thread */ - os_cond_signal(&exec_env->wait_cond); - os_mutex_unlock(&exec_env->wait_lock); + /* + * wasm gdbserver created, the execution thread + * doesn't need to wait for the debugger connection, + * so we wake up the execution thread before listen + */ + os_cond_signal(&debug_inst->wait_cond); + os_mutex_unlock(&debug_inst->wait_lock); + + /* wait lldb client to connect */ + if (!wasm_gdbserver_listen(control_thread->server)) { + LOG_ERROR("Failed while connecting debugger\n"); + wasm_runtime_free(control_thread->server); + return NULL; + } while (true) { os_mutex_lock(&control_thread->wait_lock); @@ -112,7 +115,7 @@ control_thread_routine(void *arg) os_mutex_unlock(&control_thread->wait_lock); } - LOG_VERBOSE("control thread of debug object %p stop\n", debug_inst); + LOG_VERBOSE("control thread of debug object [%p] stopped\n", debug_inst); return NULL; } @@ -120,12 +123,6 @@ static WASMDebugControlThread * wasm_debug_control_thread_create(WASMDebugInstance *debug_instance) { WASMDebugControlThread *control_thread; - WASMCluster *cluster = debug_instance->cluster; - WASMExecEnv *exec_env; - bh_assert(cluster); - - exec_env = bh_list_first_elem(&cluster->exec_env_list); - bh_assert(exec_env); if (!(control_thread = wasm_runtime_malloc(sizeof(WASMDebugControlThread)))) { @@ -139,18 +136,18 @@ wasm_debug_control_thread_create(WASMDebugInstance *debug_instance) debug_instance->control_thread = control_thread; - os_mutex_lock(&exec_env->wait_lock); + os_mutex_lock(&debug_instance->wait_lock); if (0 != os_thread_create(&control_thread->tid, control_thread_routine, debug_instance, APP_THREAD_STACK_SIZE_MAX)) { - os_mutex_unlock(&control_thread->wait_lock); + os_mutex_unlock(&debug_instance->wait_lock); goto fail1; } /* wait until the debug control thread ready */ - os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); - os_mutex_unlock(&exec_env->wait_lock); + os_cond_wait(&debug_instance->wait_cond, &debug_instance->wait_lock); + os_mutex_unlock(&debug_instance->wait_lock); if (!control_thread->server) goto fail1; @@ -174,7 +171,8 @@ static void wasm_debug_control_thread_destroy(WASMDebugInstance *debug_instance) { WASMDebugControlThread *control_thread = debug_instance->control_thread; - LOG_VERBOSE("control thread of debug object %p stop\n", debug_instance); + LOG_VERBOSE("stopping control thread of debug object [%p]\n", + debug_instance); control_thread->status = STOPPED; os_mutex_lock(&control_thread->wait_lock); wasm_close_gdbserver(control_thread->server); @@ -286,6 +284,15 @@ wasm_debug_instance_create(WASMCluster *cluster) return NULL; } memset(instance, 0, sizeof(WASMDebugInstance)); + + if (os_mutex_init(&instance->wait_lock) != 0) { + goto fail1; + } + + if (os_cond_init(&instance->wait_cond) != 0) { + goto fail2; + } + bh_list_init(&instance->break_point_list); instance->cluster = cluster; @@ -297,29 +304,21 @@ wasm_debug_instance_create(WASMCluster *cluster) if (!wasm_debug_control_thread_create(instance)) { LOG_ERROR("WASM Debug Engine error: failed to create control thread"); wasm_runtime_free(instance); - return NULL; + goto fail3; } - return instance; -} + wasm_cluster_set_debug_inst(cluster, instance); -static WASMDebugInstance * -wasm_cluster_get_debug_instance(WASMDebugEngine *engine, WASMCluster *cluster) -{ - WASMDebugInstance *instance; + return instance; - os_mutex_lock(&g_debug_engine->instance_list_lock); - instance = bh_list_first_elem(&engine->debug_instance_list); - while (instance) { - if (instance->cluster == cluster) { - os_mutex_unlock(&g_debug_engine->instance_list_lock); - return instance; - } - instance = bh_list_elem_next(instance); - } - os_mutex_unlock(&g_debug_engine->instance_list_lock); +fail3: + os_cond_destroy(&instance->wait_cond); +fail2: + os_mutex_destroy(&instance->wait_lock); +fail1: + wasm_runtime_free(instance); - return instance; + return NULL; } static void @@ -347,7 +346,7 @@ wasm_debug_instance_destroy(WASMCluster *cluster) return; } - instance = wasm_cluster_get_debug_instance(g_debug_engine, cluster); + instance = cluster->debug_inst; if (instance) { /* destroy control thread */ wasm_debug_control_thread_destroy(instance); @@ -359,7 +358,11 @@ wasm_debug_instance_destroy(WASMCluster *cluster) /* destroy all breakpoints */ wasm_debug_instance_destroy_breakpoints(instance); + os_mutex_destroy(&instance->wait_lock); + os_cond_destroy(&instance->wait_cond); + wasm_runtime_free(instance); + cluster->debug_inst = NULL; } } @@ -434,47 +437,78 @@ wasm_debug_instance_get_tids(WASMDebugInstance *instance, uint64 tids[], int len) { WASMExecEnv *exec_env; - int i = 0; + int i = 0, threads_num = 0; if (!instance) return 0; exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); while (exec_env && i < len) { - tids[i++] = exec_env->handle; + /* Some threads may not be ready */ + if (exec_env->handle != 0) { + tids[i++] = exec_env->handle; + threads_num++; + } exec_env = bh_list_elem_next(exec_env); } - LOG_VERBOSE("find %d tids\n", i); - return i; + LOG_VERBOSE("find %d tids\n", threads_num); + return threads_num; } -uint64 -wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 tid, - uint32 *status) +static WASMExecEnv * +get_stopped_thread(WASMCluster *cluster) { WASMExecEnv *exec_env; - WASMExecEnv *last_exec_env = NULL; - exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + exec_env = bh_list_first_elem(&cluster->exec_env_list); while (exec_env) { - last_exec_env = exec_env; - if (instance->current_tid != 0 - && last_exec_env->handle == instance->current_tid) { - break; + if (exec_env->current_status->running_status != STATUS_RUNNING) { + return exec_env; } exec_env = bh_list_elem_next(exec_env); } - if (last_exec_env) { - wasm_cluster_wait_thread_status(last_exec_env, status); - if (instance->current_tid == 0) - instance->current_tid = last_exec_env->handle; - return last_exec_env->handle; + return NULL; +} + +uint64 +wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 tid, + uint32 *status) +{ + WASMExecEnv *exec_env = NULL; + + os_mutex_lock(&instance->wait_lock); + while ((instance->cluster->exec_env_list.len != 0) + && ((exec_env = get_stopped_thread(instance->cluster)) == NULL)) { + os_cond_wait(&instance->wait_cond, &instance->wait_lock); } - else { - *status = ~0; + os_mutex_unlock(&instance->wait_lock); + + /* If cluster has no exec_env, then this whole cluster is exiting */ + if (instance->cluster->exec_env_list.len == 0) { + *status = 0; return 0; } + + instance->current_tid = exec_env->handle; + *status = exec_env->current_status->signal_flag; + return exec_env->handle; +} + +uint32 +wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, uint64 tid) +{ + WASMExecEnv *exec_env = NULL; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + while (exec_env) { + if (exec_env->handle == tid) { + return exec_env->current_status->signal_flag; + } + exec_env = bh_list_elem_next(exec_env); + } + + return 0; } void diff --git a/core/iwasm/libraries/debug-engine/debug_engine.h b/core/iwasm/libraries/debug-engine/debug_engine.h index 91cdfc81f8..c8c15fe0da 100644 --- a/core/iwasm/libraries/debug-engine/debug_engine.h +++ b/core/iwasm/libraries/debug-engine/debug_engine.h @@ -42,6 +42,8 @@ typedef struct WASMDebugInstance { WASMCluster *cluster; uint32 id; korp_tid current_tid; + korp_mutex wait_lock; + korp_cond wait_cond; } WASMDebugInstance; typedef enum WASMDebugEventKind { @@ -160,6 +162,9 @@ uint64 wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 tid, uint32 *status); +uint32 +wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, uint64 tid); + bool wasm_debug_instance_singlestep(WASMDebugInstance *instance, uint64 tid); diff --git a/core/iwasm/libraries/debug-engine/gdbserver.c b/core/iwasm/libraries/debug-engine/gdbserver.c index 6e1eec2ff5..5e584ec846 100644 --- a/core/iwasm/libraries/debug-engine/gdbserver.c +++ b/core/iwasm/libraries/debug-engine/gdbserver.c @@ -51,17 +51,18 @@ static struct packet_handler_elem packet_handler_table[255] = { }; WASMGDBServer * -wasm_launch_gdbserver(char *host, int port) +wasm_create_gdbserver(char *host, int *port) { int listen_fd = -1; const int one = 1; struct sockaddr_in addr; socklen_t socklen; int ret; - int sockt_fd = 0; WASMGDBServer *server; + bh_assert(port); + if (!(server = wasm_runtime_malloc(sizeof(WASMGDBServer)))) { LOG_ERROR("wasm gdb server error: failed to allocate memory"); return NULL; @@ -90,7 +91,7 @@ wasm_launch_gdbserver(char *host, int port) addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(host); - addr.sin_port = htons(port); + addr.sin_port = htons(*port); ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { @@ -103,35 +104,51 @@ wasm_launch_gdbserver(char *host, int port) LOG_ERROR("%s", strerror(errno)); goto fail; } + LOG_WARNING("Debug server listening on %s:%d\n", host, + ntohs(addr.sin_port)); + + *port = ntohs(addr.sin_port); + server->listen_fd = listen_fd; - LOG_WARNING("Listening on %s:%d\n", host, ntohs(addr.sin_port)); + return server; + +fail: + if (listen_fd >= 0) { + shutdown(listen_fd, SHUT_RDWR); + close(listen_fd); + } + if (server) + wasm_runtime_free(server); + return NULL; +} - ret = listen(listen_fd, 1); +bool +wasm_gdbserver_listen(WASMGDBServer *server) +{ + int ret; + int sockt_fd = 0; + + ret = listen(server->listen_fd, 1); if (ret < 0) { LOG_ERROR("wasm gdb server error: listen() failed"); goto fail; } - server->listen_fd = listen_fd; - - sockt_fd = accept(listen_fd, NULL, NULL); + sockt_fd = accept(server->listen_fd, NULL, NULL); if (sockt_fd < 0) { LOG_ERROR("wasm gdb server error: accept() failed"); goto fail; } + LOG_VERBOSE("accept gdb client"); server->socket_fd = sockt_fd; server->noack = false; - return server; + return true; fail: - if (listen_fd >= 0) { - shutdown(listen_fd, SHUT_RDWR); - close(listen_fd); - } - if (server) - wasm_runtime_free(server); - return NULL; + shutdown(server->listen_fd, SHUT_RDWR); + close(server->listen_fd); + return false; } void diff --git a/core/iwasm/libraries/debug-engine/gdbserver.h b/core/iwasm/libraries/debug-engine/gdbserver.h index db90b0195f..0665dd96ca 100644 --- a/core/iwasm/libraries/debug-engine/gdbserver.h +++ b/core/iwasm/libraries/debug-engine/gdbserver.h @@ -33,7 +33,10 @@ typedef struct WASMGDBServer { } WASMGDBServer; WASMGDBServer * -wasm_launch_gdbserver(char *addr, int port); +wasm_create_gdbserver(char *addr, int *port); + +bool +wasm_gdbserver_listen(WASMGDBServer *server); void wasm_close_gdbserver(WASMGDBServer *server); diff --git a/core/iwasm/libraries/debug-engine/handler.c b/core/iwasm/libraries/debug-engine/handler.c index 0e2701207f..0b3744c23e 100644 --- a/core/iwasm/libraries/debug-engine/handler.c +++ b/core/iwasm/libraries/debug-engine/handler.c @@ -17,6 +17,9 @@ #define MAX_PACKET_SIZE (0x20000) static char tmpbuf[MAX_PACKET_SIZE]; +static void +send_thread_stop_status(WASMGDBServer *server, uint32_t status, uint64_t tid); + void handle_generay_set(WASMGDBServer *server, char *payload) { @@ -261,6 +264,20 @@ handle_generay_query(WASMGDBServer *server, char *payload) if (args && (!strcmp(name, "WasmGlobal"))) { porcess_wasm_global(server, args); } + + if (!strcmp(name, "Offsets")) { + write_packet(server, ""); + } + + if (!strncmp(name, "ThreadStopInfo", strlen("ThreadStopInfo"))) { + int32 prefix_len = strlen("ThreadStopInfo"); + uint64 tid = strtol(name + prefix_len, NULL, 16); + + uint32 status = wasm_debug_instance_get_thread_status( + server->thread->debug_instance, tid); + + send_thread_stop_status(server, status, tid); + } } static void @@ -332,19 +349,32 @@ handle_v_packet(WASMGDBServer *server, char *payload) write_packet(server, "vCont;c;C;s;S;"); if (!strcmp("Cont", name)) { - if (args && args[0] == 's') { - char *numstring = strchr(args, ':'); - if (numstring) { - *numstring++ = '\0'; - uint64_t tid = strtol(numstring, NULL, 16); - wasm_debug_instance_set_cur_thread( - (WASMDebugInstance *)server->thread->debug_instance, tid); - wasm_debug_instance_singlestep( - (WASMDebugInstance *)server->thread->debug_instance, tid); - tid = wasm_debug_instance_wait_thread( - (WASMDebugInstance *)server->thread->debug_instance, tid, - &status); - send_thread_stop_status(server, status, tid); + if (args) { + if (args[0] == 's' || args[0] == 'c') { + char *numstring = strchr(args, ':'); + if (numstring) { + *numstring++ = '\0'; + uint64_t tid = strtol(numstring, NULL, 16); + wasm_debug_instance_set_cur_thread( + (WASMDebugInstance *)server->thread->debug_instance, + tid); + + if (args[0] == 's') { + wasm_debug_instance_singlestep( + (WASMDebugInstance *)server->thread->debug_instance, + tid); + } + else { + wasm_debug_instance_continue( + (WASMDebugInstance *) + server->thread->debug_instance); + } + + tid = wasm_debug_instance_wait_thread( + (WASMDebugInstance *)server->thread->debug_instance, + tid, &status); + send_thread_stop_status(server, status, tid); + } } } } diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 6bc2074267..a47e319414 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -332,7 +332,7 @@ create_cluster_info(WASMCluster *cluster) if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) { return NULL; } - memset(node, 0, sizeof(WASMCluster)); + memset(node, 0, sizeof(ClusterInfoNode)); node->thread_list = &node->thread_list_head; ret = bh_list_init(node->thread_list); diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 87a24bef08..b2524df4de 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -5,6 +5,10 @@ #include "thread_manager.h" +#if WASM_ENABLE_DEBUG_INTERP != 0 +#include "debug_engine.h" +#endif + typedef struct { bh_list_link l; void (*destroy_cb)(WASMCluster *); @@ -227,6 +231,11 @@ wasm_cluster_destroy(WASMCluster *cluster) wasm_runtime_free(cluster->stack_tops); if (cluster->stack_segment_occupied) wasm_runtime_free(cluster->stack_segment_occupied); + +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_debug_instance_destroy(cluster); +#endif + wasm_runtime_free(cluster); } @@ -488,31 +497,18 @@ wasm_cluster_create_exenv_status() WASMCurrentEnvStatus *status; if (!(status = wasm_runtime_malloc(sizeof(WASMCurrentEnvStatus)))) { - goto fail; + return NULL; } - if (os_mutex_init(&status->wait_lock) != 0) - goto fail1; - if (os_cond_init(&status->wait_cond) != 0) - goto fail2; status->step_count = 0; status->signal_flag = 0; status->running_status = 0; return status; - -fail2: - os_mutex_destroy(&status->wait_lock); -fail1: - wasm_runtime_free(status); -fail: - return NULL; } void wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status) { - os_mutex_destroy(&status->wait_lock); - os_cond_destroy(&status->wait_cond); wasm_runtime_free(status); } @@ -530,28 +526,33 @@ wasm_cluster_clear_thread_signal(WASMExecEnv *exec_env) } void -wasm_cluster_wait_thread_status(WASMExecEnv *exec_env, uint32 *status) +wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo) { - os_mutex_lock(&exec_env->current_status->wait_lock); - while (wasm_cluster_thread_is_running(exec_env)) { - os_cond_wait(&exec_env->current_status->wait_cond, - &exec_env->current_status->wait_lock); - } - *status = exec_env->current_status->signal_flag; - os_mutex_unlock(&exec_env->current_status->wait_lock); + exec_env->current_status->signal_flag = signo; } -void -wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo) +static void +notify_debug_instance(WASMExecEnv *exec_env) { - exec_env->current_status->signal_flag = signo; + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + if (!cluster->debug_inst) { + return; + } + + os_mutex_lock(&cluster->debug_inst->wait_lock); + os_cond_signal(&cluster->debug_inst->wait_cond); + os_mutex_unlock(&cluster->debug_inst->wait_lock); } void wasm_cluster_thread_stopped(WASMExecEnv *exec_env) { exec_env->current_status->running_status = STATUS_STOP; - os_cond_signal(&exec_env->current_status->wait_cond); + notify_debug_instance(exec_env); } void @@ -578,7 +579,7 @@ void wasm_cluster_thread_exited(WASMExecEnv *exec_env) { exec_env->current_status->running_status = STATUS_EXIT; - os_cond_signal(&exec_env->current_status->wait_cond); + notify_debug_instance(exec_env); } void @@ -595,7 +596,14 @@ wasm_cluster_thread_step(WASMExecEnv *exec_env) exec_env->current_status->running_status = STATUS_STEP; os_cond_signal(&exec_env->wait_cond); } -#endif + +void +wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst) +{ + cluster->debug_inst = inst; +} + +#endif /* end of WASM_ENABLE_DEBUG_INTERP */ int32 wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index 0baa4f5efe..ca1cd8f804 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -39,6 +39,8 @@ typedef struct WASMCurrentEnvStatus { korp_cond wait_cond; } WASMCurrentEnvStatus; +typedef struct WASMDebugInstance WASMDebugInstance; + WASMCurrentEnvStatus * wasm_cluster_create_exenv_status(); @@ -69,6 +71,9 @@ wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo); void wasm_cluster_thread_step(WASMExecEnv *exec_env); +void +wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst); + #endif typedef struct WASMCluster { struct WASMCluster *next; @@ -84,6 +89,9 @@ typedef struct WASMCluster { uint32 stack_size; /* Record which segments are occupied */ bool *stack_segment_occupied; +#if WASM_ENABLE_DEBUG_INTERP != 0 + WASMDebugInstance *debug_inst; +#endif } WASMCluster; void diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 881da8b6cf..a93a4b7883 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -146,6 +146,10 @@ Currently we only profile the memory consumption of module, module_instance and > Note: The WAMR application entry (`core/iwasm/common/wasm_application.c`) encapsulate some common process to instantiate, execute the wasm functions and print the results. Some platform related APIs are used in these functions, so you can enable this flag to exclude this file if your platform doesn't support those APIs. > *Don't enable this flag if you are building `product-mini`* +#### **Enable source debugging features** +- **WAMR_BUILD_DEBUG_INTERP**=1/0, default to 0 if not set +> Note: There are some other setup required by source debugging, please refer to [source_debugging.md](./source_debugging.md) for more details. + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/doc/source_debugging.md b/doc/source_debugging.md index 6d0021b430..cd72dcb1eb 100644 --- a/doc/source_debugging.md +++ b/doc/source_debugging.md @@ -89,3 +89,51 @@ lldb-12 iwasm -- test.aot ``` Then you can use lldb commands to debug both wamr runtime and your wasm application in ***current terminal*** + +## Enable debugging in embedders (for interpreter) + +There are three steps to enable debugging in embedders + +1. Set the debug parameters when initializing the runtime environment: + ``` c + RuntimeInitArgs init_args; + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + /* ... */ + strcpy(init_args.ip_addr, "127.0.0.1"); + init_args.instance_port = 1234; + /* + * Or set port to 0 to use a port assigned by os + * init_args.instance_port = 0; + */ + + if (!wasm_runtime_full_init(&init_args)) { + return false; + } + ``` + +2. Use `wasm_runtime_start_debug_instance` to create the debug instance: + ``` c + /* + initialization, loading and instantiating + ... + */ + exec_env = wasm_runtime_create_exec_env(module_inst, stack_size); + uint32_t debug_port = wasm_runtime_start_debug_instance(); + ``` + +3. Enable source debugging features during building + + You can use `-DWAMR_BUILD_DEBUG_INTERP=1` during cmake configuration + + Or you can set it directly in `cmake` files: + ``` cmake + set (WAMR_BUILD_DEBUG_INTERP 1) + ``` + +### Attentions +- Debugging `multi-thread wasm module` is not supported, if your wasm module use pthread APIs (see [pthread_library.md](./pthread_library.md)), or the embedder use `wasm_runtime_spawn_thread` to create new wasm threads, then there may be **unexpected behaviour** during debugging. + + > Note: This attention is about "wasm thread" rather than native threads. Executing wasm functions in several different native threads will **not** affect the normal behaviour of debugging feature. + +- When using source debugging features, **don't** create multiple `wasm_instance` from the same `wasm_module`, because the debugger may change the bytecode (set/unset breakpoints) of the `wasm_module`. If you do need several instance from the same bytecode, you need to copy the bytecode to a new butter, then load a new `wasm_module`, and then instantiate the new wasm module to get the new instance. diff --git a/doc/xip.md b/doc/xip.md new file mode 100644 index 0000000000..d6c5a37012 --- /dev/null +++ b/doc/xip.md @@ -0,0 +1,14 @@ +# WAMR XIP (Execution In Place) feature introduction + +Some IoT devices may require to run the AOT file from flash or ROM which is read-only, so as to reduce the memory consumption, or resolve the issue that there is no executable memory available to run AOT code. In such case, the AOT code inside the AOT file shouldn't be duplicated into memory and shouldn't be modified (or patched) by the AOT relocations. To address this, WAMR implements the XIP (Execution In Place) feature, which generates the AOT relocations as few as possible: +- In the AOT code, an AOT function calls other functions with indirect mode: it doesn't call other functions directly, but looks up their pointers from the function pointer table passed by its first argument exec_env, and then calls the function pointer found. By this way the relocations to other functions are eliminated. +- Eliminate the calls to the LLVM intrinsic functions, or, replace calling them with calling runtime self implemented functions instead, e.g. the calling to `llvm.experimental.constrained.fadd.f32` is replaced by the calling to `aot_intrinsic_fadd_f32`. + +The XIP file is an AOT file without (or with few) relocations to patch the AOT code (or text section). Developer can use the option `--enable-indirect-mode --disable-llvm-intrinsics` for wamrc to generate the AOT file, e.g.: +```bash +wamrc --enable-indirect-mode --disable-llvm-intrinsics -o +``` + +## Known issues + +There may be some relocations to the ".rodata" like sections which require to patch the AOT code. More work will be done to resolve it in the future. diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index b9fafe4529..1407d536cf 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -52,6 +52,8 @@ typedef struct EnclaveModule { uint32 wasi_env_list_size; char **wasi_argv; uint32 wasi_argc; + bool is_xip_file; + uint32 total_size_mapped; } EnclaveModule; #if WASM_ENABLE_SPEC_TEST == 0 @@ -127,28 +129,57 @@ handle_cmd_load_module(uint64 *args, uint32 argc) uint32 error_buf_size = *(uint32 *)args++; uint64 total_size = sizeof(EnclaveModule) + (uint64)wasm_file_size; EnclaveModule *enclave_module; + bool is_xip_file = false; bh_assert(argc == 4); - if (total_size >= UINT32_MAX - || !(enclave_module = - (EnclaveModule *)wasm_runtime_malloc((uint32)total_size))) { - set_error_buf(error_buf, error_buf_size, - "WASM module load failed: " - "allocate memory failed."); - *(void **)args_org = NULL; - return; +#if WASM_ENABLE_AOT != 0 + is_xip_file = wasm_runtime_is_xip_file((uint8 *)wasm_file, wasm_file_size); +#endif + + if (!is_xip_file) { + if (total_size >= UINT32_MAX + || !(enclave_module = (EnclaveModule *)wasm_runtime_malloc( + (uint32)total_size))) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: " + "allocate memory failed."); + *(void **)args_org = NULL; + return; + } + memset(enclave_module, 0, (uint32)total_size); + } + else { + int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; + int map_flags = MMAP_MAP_NONE; + + if (total_size >= UINT32_MAX + || !(enclave_module = (EnclaveModule *)os_mmap( + NULL, (uint32)total_size, map_prot, map_flags))) { + set_error_buf(error_buf, error_buf_size, + "WASM module load failed: mmap memory failed."); + *(void **)args_org = NULL; + return; + } + memset(enclave_module, 0, (uint32)total_size); + enclave_module->is_xip_file = true; + enclave_module->total_size_mapped = (uint32)total_size; } - memset(enclave_module, 0, (uint32)total_size); enclave_module->wasm_file = (uint8 *)enclave_module + sizeof(EnclaveModule); bh_memcpy_s(enclave_module->wasm_file, wasm_file_size, wasm_file, wasm_file_size); + if (is_xip_file) { + enclave_module->is_xip_file = true; + } if (!(enclave_module->module = wasm_runtime_load(enclave_module->wasm_file, wasm_file_size, error_buf, error_buf_size))) { - wasm_runtime_free(enclave_module); + if (!is_xip_file) + wasm_runtime_free(enclave_module); + else + os_munmap(enclave_module, (uint32)total_size); *(void **)args_org = NULL; return; } @@ -170,7 +201,10 @@ handle_cmd_unload_module(uint64 *args, uint32 argc) wasm_runtime_free(enclave_module->wasi_arg_buf); wasm_runtime_unload(enclave_module->module); - wasm_runtime_free(enclave_module); + if (!enclave_module->is_xip_file) + wasm_runtime_free(enclave_module); + else + os_munmap(enclave_module, enclave_module->total_size_mapped); LOG_VERBOSE("Unload module success.\n"); } diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index 179dd3e0e3..2392d7a667 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -34,8 +34,6 @@ print_help() printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" " that runs commands in the form of \"FUNC ARG...\"\n"); - printf(" --xip Enable XIP (Execution In Place) mode to run AOT file\n" - " generated with \"--enable-indirect-mode\" flag\n"); #if WASM_ENABLE_LIBC_WASI != 0 printf(" --env= Pass wasi environment variables with \"key=value\"\n"); printf(" to the program, for example:\n"); @@ -240,7 +238,7 @@ main(int argc, char *argv[]) int log_verbose_level = 2; #endif bool is_repl_mode = false; - bool is_xip_mode = false; + bool is_xip_file = false; #if WASM_ENABLE_LIBC_WASI != 0 const char *dir_list[8] = { NULL }; uint32 dir_list_size = 0; @@ -273,9 +271,6 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--repl")) { is_repl_mode = true; } - else if (!strcmp(argv[0], "--xip")) { - is_xip_mode = true; - } else if (!strncmp(argv[0], "--stack-size=", 13)) { if (argv[0][13] == '\0') return print_help(); @@ -392,10 +387,11 @@ main(int argc, char *argv[]) (uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size))) goto fail1; - if (is_xip_mode) { +#if WASM_ENABLE_AOT != 0 + if (wasm_runtime_is_xip_file(wasm_file_buf, wasm_file_size)) { uint8 *wasm_file_mapped; int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; - int map_flags = MMAP_MAP_NONE; + int map_flags = MMAP_MAP_32BIT; if (!(wasm_file_mapped = os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) { @@ -408,7 +404,9 @@ main(int argc, char *argv[]) wasm_file_size); wasm_runtime_free(wasm_file_buf); wasm_file_buf = wasm_file_mapped; + is_xip_file = true; } +#endif #if WASM_ENABLE_MULTI_MODULE != 0 wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer); @@ -450,7 +448,7 @@ main(int argc, char *argv[]) fail2: /* free the file buffer */ - if (!is_xip_mode) + if (!is_xip_file) wasm_runtime_free(wasm_file_buf); else os_munmap(wasm_file_buf, wasm_file_size); diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index ed1c44b6ce..9f88c416bf 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -51,6 +51,7 @@ def ignore_the_case( multi_module_flag=False, multi_thread_flag=False, simd_flag=False, + xip_flag=False, ): if case_name in ["comments", "inline-module", "names"]: return True @@ -100,6 +101,7 @@ def test_case( multi_module_flag=False, multi_thread_flag=False, simd_flag=False, + xip_flag=False, clean_up_flag=True, verbose_flag=True, ): @@ -114,6 +116,7 @@ def test_case( multi_module_flag, multi_thread_flag, simd_flag, + xip_flag, ): return True @@ -139,6 +142,9 @@ def test_case( if simd_flag: CMD.append("--simd") + if xip_flag: + CMD.append("--xip") + if not clean_up_flag: CMD.append("--no_cleanup") @@ -195,6 +201,7 @@ def test_suite( multi_module_flag=False, multi_thread_flag=False, simd_flag=False, + xip_flag=False, clean_up_flag=True, verbose_flag=True, ): @@ -217,6 +224,7 @@ def test_suite( multi_module_flag, multi_thread_flag, simd_flag, + xip_flag, clean_up_flag, verbose_flag, ) @@ -239,6 +247,7 @@ def test_suite_parallelly( multi_module_flag=False, multi_thread_flag=False, simd_flag=False, + xip_flag=False, clean_up_flag=False, verbose_flag=False, ): @@ -266,6 +275,7 @@ def test_suite_parallelly( multi_module_flag, multi_thread_flag, simd_flag, + xip_flag, clean_up_flag, verbose_flag, ], @@ -323,6 +333,13 @@ def main(): dest="simd_flag", help="Running with the SIMD feature", ) + parser.add_argument( + "-X", + action="store_true", + default=False, + dest="xip_flag", + help="Running with the XIP feature", + ) parser.add_argument( "-t", action="store_true", @@ -387,6 +404,7 @@ def main(): options.multi_module_flag, options.multi_thread_flag, options.simd_flag, + options.xip_flag, options.clean_up_flag, options.verbose_flag, ) @@ -403,6 +421,7 @@ def main(): options.multi_module_flag, options.multi_thread_flag, options.simd_flag, + options.xip_flag, options.clean_up_flag, options.verbose_flag, ) @@ -419,6 +438,7 @@ def main(): options.multi_module_flag, options.multi_thread_flag, options.simd_flag, + options.xip_flag, options.clean_up_flag, options.verbose_flag, ) diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index fe24e00579..7db0c042aa 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -210,6 +210,9 @@ def assert_prompt(runner, prompts, timeout, is_need_execute_result): parser.add_argument('--simd', default=False, action='store_true', help="Enable SIMD") +parser.add_argument('--xip', default=False, action='store_true', + help="Enable XIP") + parser.add_argument('--multi-thread', default=False, action='store_true', help="Enable Multi-thread") @@ -942,6 +945,10 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r): if not opts.simd: cmd.append("--disable-simd") + if opts.xip: + cmd.append("--enable-indirect-mode") + cmd.append("--disable-llvm-intrinsics") + if opts.multi_thread: cmd.append("--enable-multi-thread") diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 7c7ff1b268..0815567eea 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -17,9 +17,10 @@ function help() echo "-s {suite_name} test only one suite (spec)" echo "-m set compile target of iwasm(x86_64\x86_32\armv7_vfp\thumbv7_vfp\riscv64_lp64d\riscv64_lp64)" echo "-t set compile type of iwasm(classic-interp\fast-interp\jit\aot)" - echo "-M enable the multi module feature" + echo "-M enable multi module feature" echo "-p enable multi thread feature" - echo "-S enable SIMD" + echo "-S enable SIMD feature" + echo "-X enable XIP feature" echo "-x test SGX" echo "-b use the wabt binary release package instead of compiling from the source code" echo "-P run the spec test parallelly" @@ -35,13 +36,14 @@ ENABLE_MULTI_MODULE=0 ENABLE_MULTI_THREAD=0 COLLECT_CODE_COVERAGE=0 ENABLE_SIMD=0 +ENABLE_XIP=0 #unit test case arrary TEST_CASE_ARR=() SGX_OPT="" PLATFORM=$(uname -s | tr A-Z a-z) PARALLELISM=0 -while getopts ":s:cabt:m:MCpSxP" opt +while getopts ":s:cabt:m:MCpSXxP" opt do OPT_PARSED="TRUE" case $opt in @@ -106,6 +108,10 @@ do echo "enable SIMD feature" ENABLE_SIMD=1 ;; + X) + echo "enable XIP feature" + ENABLE_XIP=1 + ;; x) echo "test SGX" SGX_OPT="--sgx" @@ -378,7 +384,11 @@ function spec_test() fi if [[ ${ENABLE_MULTI_THREAD} == 1 ]]; then - ARGS_FOR_SPEC_TEST+="-p " + ARGS_FOR_SPEC_TEST+="-p " + fi + + if [[ ${ENABLE_XIP} == 1 ]]; then + ARGS_FOR_SPEC_TEST+="-X " fi # require warmc only in aot mode From d6f90ac7823f821745ddcb523002ddd910dbabf5 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Sat, 11 Dec 2021 02:20:14 +0800 Subject: [PATCH 2/5] Fix compile issue --- .../platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 5e5dc0454f..5a05d298e0 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -194,7 +194,6 @@ handle_cmd_load_module(uint64 *args, uint32 argc) uint32 error_buf_size = *(uint32 *)args++; uint64 total_size = sizeof(EnclaveModule) + (uint64)wasm_file_size; EnclaveModule *enclave_module; - bool is_xip_file = false; bh_assert(argc == 4); From d4fc644cb7b31129cd8df90a0e545a00650b0b7b Mon Sep 17 00:00:00 2001 From: "liang.he" Date: Wed, 23 Feb 2022 17:09:14 +0800 Subject: [PATCH 3/5] Partly Implement Berkeley Socket API for libc-wasi (#836) Refer to [ Networking API design](https://github.com/WebAssembly/WASI/issues/370) and [feat(socket): berkeley socket API v2](https://github.com/WebAssembly/WASI/pull/459) Support the socket API of synchronous mode, including socket/bind/listen/accept/send/recv/close/shutdown, the asynchronous mode isn't supported yet. Support adding `--addr-pool=` argument for command line to identify the valid ip address range. And add the sample. --- core/iwasm/aot/aot_runtime.c | 1 + core/iwasm/common/wasm_runtime_common.c | 81 +++- core/iwasm/common/wasm_runtime_common.h | 11 +- core/iwasm/include/wasm_export.h | 4 + core/iwasm/interpreter/wasm.h | 3 + core/iwasm/interpreter/wasm_runtime.c | 1 + .../lib-socket/inc/wasi_socket_ext.h | 410 ++++++++++++++++++ .../lib-socket/lib_socket_wasi.cmake | 9 + .../lib-socket/src/wasi/wasi_socket_ext.c | 180 ++++++++ .../libraries/libc-wasi/libc_wasi_wrapper.c | 317 +++++++++++--- .../libraries/libc-wasi/libc_wasi_wrapper.h | 49 ++- .../include/wasmtime_ssp.h | 195 +++++++-- .../sandboxed-system-primitives/src/posix.c | 395 ++++++++++++++--- .../sandboxed-system-primitives/src/posix.h | 16 + .../sandboxed-system-primitives/src/rights.h | 21 +- .../platform/common/posix/posix_socket.c | 37 ++ .../platform/include/platform_api_extension.h | 23 + core/shared/platform/linux-sgx/sgx_socket.c | 68 +++ core/shared/platform/windows/win_socket.c | 10 + product-mini/platforms/posix/main.c | 31 +- samples/network/CMakeLists.txt | 92 ++++ samples/network/wasm-src/CMakeLists.txt | 71 +++ samples/network/wasm-src/tcp_client.c | 53 +++ samples/network/wasm-src/tcp_server.c | 93 ++++ test-tools/build-wasi-sdk/include/.gitkeep | 0 25 files changed, 1964 insertions(+), 207 deletions(-) create mode 100644 core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h create mode 100644 core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake create mode 100644 core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c create mode 100644 samples/network/CMakeLists.txt create mode 100644 samples/network/wasm-src/CMakeLists.txt create mode 100644 samples/network/wasm-src/tcp_client.c create mode 100644 samples/network/wasm-src/tcp_server.c delete mode 100644 test-tools/build-wasi-sdk/include/.gitkeep diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 4ff63d465d..c09ca46b69 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1018,6 +1018,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, module->wasi_args.dir_list, module->wasi_args.dir_count, module->wasi_args.map_dir_list, module->wasi_args.map_dir_count, module->wasi_args.env, module->wasi_args.env_count, + module->wasi_args.addr_pool, module->wasi_args.addr_count, module->wasi_args.argv, module->wasi_args.argc, module->wasi_args.stdio[0], module->wasi_args.stdio[1], module->wasi_args.stdio[2], error_buf, error_buf_size)) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index be13d05c02..d29176285b 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -1969,14 +1969,36 @@ wasm_runtime_set_wasi_args(WASMModuleCommon *module, const char *dir_list[], argc, -1, -1, -1); } +void +wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], + uint32 addr_pool_size) +{ + WASIArguments *wasi_args = NULL; + +#if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0 + if (module->module_type == Wasm_Module_Bytecode) + wasi_args = &((WASMModule *)module)->wasi_args; +#endif +#if WASM_ENABLE_AOT != 0 + if (module->module_type == Wasm_Module_AoT) + wasi_args = &((AOTModule *)module)->wasi_args; +#endif + + if (wasi_args) { + wasi_args->addr_pool = addr_pool; + wasi_args->addr_count = addr_pool_size; + } +} + #if WASM_ENABLE_UVWASI == 0 bool wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *dir_list[], uint32 dir_count, const char *map_dir_list[], uint32 map_dir_count, - const char *env[], uint32 env_count, char *argv[], - uint32 argc, int stdinfd, int stdoutfd, int stderrfd, - char *error_buf, uint32 error_buf_size) + const char *env[], uint32 env_count, + const char *addr_pool[], uint32 addr_pool_size, + char *argv[], uint32 argc, int stdinfd, int stdoutfd, + int stderrfd, char *error_buf, uint32 error_buf_size) { WASIContext *wasi_ctx; char *argv_buf = NULL; @@ -1988,8 +2010,10 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, struct fd_table *curfds = NULL; struct fd_prestats *prestats = NULL; struct argv_environ_values *argv_environ = NULL; + struct addr_pool *apool = NULL; bool fd_table_inited = false, fd_prestats_inited = false; bool argv_environ_inited = false; + bool addr_pool_inited = false; __wasi_fd_t wasm_fd = 3; int32 raw_fd; char *path, resolved_path[PATH_MAX]; @@ -2063,7 +2087,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, if (!(curfds = wasm_runtime_malloc(sizeof(struct fd_table))) || !(prestats = wasm_runtime_malloc(sizeof(struct fd_prestats))) || !(argv_environ = - wasm_runtime_malloc(sizeof(struct argv_environ_values)))) { + wasm_runtime_malloc(sizeof(struct argv_environ_values))) + || !(apool = wasm_runtime_malloc(sizeof(struct addr_pool)))) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: allocate memory failed"); goto fail; @@ -2094,6 +2119,14 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, } argv_environ_inited = true; + if (!addr_pool_init(apool)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: " + "init the address pool failed"); + goto fail; + } + addr_pool_inited = true; + /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */ if (!fd_table_insert_existing(curfds, 0, (stdinfd != -1) ? stdinfd : 0) || !fd_table_insert_existing(curfds, 1, (stdoutfd != -1) ? stdoutfd : 1) @@ -2128,9 +2161,34 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, fd_prestats_insert(prestats, dir_list[i], wasm_fd); } + /* addr_pool(textual) -> apool */ + for (i = 0; i < addr_pool_size; i++) { + char *cp, *address, *mask; + bool ret = false; + + cp = bh_strdup(addr_pool[i]); + if (!cp) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: copy address failed"); + goto fail; + } + + address = strtok(cp, "/"); + mask = strtok(NULL, "/"); + + ret = addr_pool_insert(apool, address, (uint8)(atoi(mask))); + wasm_runtime_free(cp); + if (!ret) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: store address failed"); + goto fail; + } + } + wasi_ctx->curfds = curfds; wasi_ctx->prestats = prestats; wasi_ctx->argv_environ = argv_environ; + wasi_ctx->addr_pool = apool; wasi_ctx->argv_buf = argv_buf; wasi_ctx->argv_list = argv_list; wasi_ctx->env_buf = env_buf; @@ -2145,12 +2203,16 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, fd_prestats_destroy(prestats); if (fd_table_inited) fd_table_destroy(curfds); + if (addr_pool_inited) + addr_pool_destroy(apool); if (curfds) wasm_runtime_free(curfds); if (prestats) wasm_runtime_free(prestats); if (argv_environ) wasm_runtime_free(argv_environ); + if (apool) + wasm_runtime_free(apool); if (argv_buf) wasm_runtime_free(argv_buf); if (argv_list) @@ -2208,9 +2270,10 @@ bool wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *dir_list[], uint32 dir_count, const char *map_dir_list[], uint32 map_dir_count, - const char *env[], uint32 env_count, char *argv[], - uint32 argc, int stdinfd, int stdoutfd, int stderrfd, - char *error_buf, uint32 error_buf_size) + const char *env[], uint32 env_count, + const char *addr_pool[], uint32 addr_pool_size, + char *argv[], uint32 argc, int stdinfd, int stdoutfd, + int stderrfd, char *error_buf, uint32 error_buf_size) { uvwasi_t *uvwasi = NULL; uvwasi_options_t init_options; @@ -2373,6 +2436,10 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) fd_prestats_destroy(wasi_ctx->prestats); wasm_runtime_free(wasi_ctx->prestats); } + if (wasi_ctx->addr_pool) { + addr_pool_destroy(wasi_ctx->addr_pool); + wasm_runtime_free(wasi_ctx->addr_pool); + } if (wasi_ctx->argv_buf) wasm_runtime_free(wasi_ctx->argv_buf); if (wasi_ctx->argv_list) diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index c84463aa20..8be142fe8a 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -352,6 +352,7 @@ typedef struct WASIContext { struct fd_table *curfds; struct fd_prestats *prestats; struct argv_environ_values *argv_environ; + struct addr_pool *addr_pool; char *argv_buf; char **argv_list; char *env_buf; @@ -717,9 +718,10 @@ bool wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *dir_list[], uint32 dir_count, const char *map_dir_list[], uint32 map_dir_count, - const char *env[], uint32 env_count, char *argv[], - uint32 argc, int stdinfd, int stdoutfd, int stderrfd, - char *error_buf, uint32 error_buf_size); + const char *env[], uint32 env_count, + const char *addr_pool[], uint32 addr_pool_size, + char *argv[], uint32 argc, int stdinfd, int stdoutfd, + int stderrfd, char *error_buf, uint32 error_buf_size); void wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst); @@ -731,6 +733,9 @@ wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst, WASIContext * wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst); +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], + uint32 addr_pool_size); #endif /* end of WASM_ENABLE_LIBC_WASI */ #if WASM_ENABLE_REF_TYPES != 0 diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 6b66953407..2d81f30cdd 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -347,6 +347,10 @@ wasm_runtime_set_wasi_args(wasm_module_t module, const char *env[], uint32_t env_count, char *argv[], int argc); +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], + uint32_t addr_pool_size); + /** * Instantiate a WASM module. * diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 6db1a70557..bad6e9aa77 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -305,6 +305,9 @@ typedef struct WASIArguments { uint32 map_dir_count; const char **env; uint32 env_count; + /* in CIDR noation */ + const char **addr_pool; + uint32 addr_count; char **argv; uint32 argc; int stdio[3]; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 2de827c802..774bccfb37 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1522,6 +1522,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, module->wasi_args.dir_list, module->wasi_args.dir_count, module->wasi_args.map_dir_list, module->wasi_args.map_dir_count, module->wasi_args.env, module->wasi_args.env_count, + module->wasi_args.addr_pool, module->wasi_args.addr_count, module->wasi_args.argv, module->wasi_args.argc, module->wasi_args.stdio[0], module->wasi_args.stdio[1], module->wasi_args.stdio[2], error_buf, error_buf_size)) { diff --git a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h new file mode 100644 index 0000000000..6f4d5d421d --- /dev/null +++ b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASI_SOCKET_EXT_H_ +#define _WASI_SOCKET_EXT_H_ + +#include +#include + +/*Be a part of */ + +typedef enum { + SOCKET_DGRAM = 0, + SOCKET_STREAM, +} __wasi_sock_type_t; + +typedef uint16_t __wasi_ip_port_t; + +typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t; + +/* n0.n1.n2.n3 */ +typedef struct __wasi_addr_ip4_t { + uint8_t n0; + uint8_t n1; + uint8_t n2; + uint8_t n3; +} __wasi_addr_ip4_t; + +typedef struct __wasi_addr_ip4_port_t { + __wasi_addr_ip4_t addr; + __wasi_ip_port_t port; +} __wasi_addr_ip4_port_t; + +typedef struct __wasi_addr_ip6_t { + uint16_t n0; + uint16_t n1; + uint16_t n2; + uint16_t n3; + uint16_t h0; + uint16_t h1; + uint16_t h2; + uint16_t h3; +} __wasi_addr_ip6_t; + +typedef struct __wasi_addr_ip6_port_t { + __wasi_addr_ip6_t addr; + __wasi_ip_port_t port; +} __wasi_addr_ip6_port_t; + +typedef struct __wasi_addr_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_port_t ip4; + __wasi_addr_ip6_port_t ip6; + } addr; +} __wasi_addr_t; + +typedef enum { INET4 = 0, INET6 } __wasi_address_family_t; + +#ifdef __wasi__ +/** + * Reimplement below POSIX APIs with __wasi_sock_XXX functions. + * + * Keep sync with + * + * + */ + +int +accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +int +bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +int +connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +int +listen(int sockfd, int backlog); + +int +socket(int domain, int type, int protocol); +#endif + +/** + * Accept a connection on a socket + * Note: This is similar to `accept` + */ +int32_t +__imported_wasi_snapshot_preview1_sock_accept(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_accept"))); + +static inline __wasi_errno_t +__wasi_sock_accept(__wasi_fd_t fd, __wasi_fd_t *fd_new) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_accept( + (int32_t)fd, (int32_t)fd_new); +} + +/** + * Returns the local address to which the socket is bound. + * + * Note: This is similar to `getsockname` in POSIX + * + * When successful, the contents of the output buffer consist of an IP address, + * either IP4 or IP6. + */ +int32_t +__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_addr_local"))); + +static inline __wasi_errno_t +__wasi_sock_addr_local(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_local( + (int32_t)fd, (int32_t)buf, (int32_t)buf_len); +} + +/** + * Returns the remote address to which the socket is connected to. + * + * Note: This is similar to `getpeername` in POSIX + * + * When successful, the contents of the output buffer consist of an IP address, + * either IP4 or IP6. + */ +int32_t +__imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_addr_remote"))); + +static inline __wasi_errno_t +__wasi_sock_addr_remote(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_remote( + (int32_t)fd, (int32_t)buf, (int32_t)buf_len); +} + +/** + * Resolves a hostname and a port to one or more IP addresses. Port is optional + * and you can pass 0 (zero) in most cases, it is used a hint for protocol. + * + * Note: This is similar to `getaddrinfo` in POSIX + * + * When successful, the contents of the output buffer consist of a sequence of + * IPv4 and/or IPv6 addresses. Each address entry consists of a addr_t object. + * + * This function fills the output buffer as much as possible, potentially + * truncating the last address entry. It is advisable that the buffer is + */ +int32_t +__imported_wasi_snapshot_preview1_addr_resolve(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("addr_resolve"))); + +static inline __wasi_errno_t +__wasi_addr_resolve(__wasi_fd_t fd, const char *host, __wasi_ip_port_t port, + uint8_t *buf, __wasi_size_t size) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_addr_resolve( + (int32_t)fd, (int32_t)host, (int32_t)port, (int32_t)buf, (int32_t)size); +} + +/** + * Bind a socket + * Note: This is similar to `bind` in POSIX using PF_INET + */ +int32_t +__imported_wasi_snapshot_preview1_sock_bind(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_bind"))); + +static inline __wasi_errno_t +__wasi_sock_bind(__wasi_fd_t fd, __wasi_addr_t *addr) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_bind( + (int32_t)fd, (int32_t)addr); +} + +/** + * Close a socket (this is an alias for `fd_close`) + * Note: This is similar to `close` in POSIX. + */ +int32_t +__imported_wasi_snapshot_preview1_sock_close(int32_t arg0) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_close"))); + +static inline __wasi_errno_t +__wasi_sock_close(__wasi_fd_t fd) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_close( + (int32_t)fd); +} + +/** + * Initiate a connection on a socket to the specified address + * Note: This is similar to `connect` in POSIX + */ + +int32_t +__imported_wasi_snapshot_preview1_sock_connect(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_connect"))); + +static inline __wasi_errno_t +__wasi_sock_connect(__wasi_fd_t fd, __wasi_addr_t *addr) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_connect( + (int32_t)fd, (int32_t)addr); +} +/** + * Retrieve the size of the receive buffer + * Note: This is similar to `getsockopt` in POSIX for SO_RCVBUF + */ + +int32_t +__imported_wasi_snapshot_preview1_sock_get_recv_buf_size(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_recv_buf_size"))); + +static inline __wasi_errno_t +__wasi_sock_get_recv_buf_size(__wasi_fd_t fd, __wasi_size_t *size) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_recv_buf_size((int32_t)fd, + (int32_t)size); +} +/** + * Retrieve status of address reuse on a socket + * Note: This is similar to `getsockopt` in POSIX for SO_REUSEADDR + */ +int32_t +__imported_wasi_snapshot_preview1_sock_get_reuse_addr(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_reuse_addr"))); + +static inline __wasi_errno_t +__wasi_sock_get_reuse_addr(__wasi_fd_t fd, uint8_t *reuse) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_reuse_addr((int32_t)fd, + (int32_t)reuse); +} + +/** + * Retrieve status of port reuse on a socket + * Note: This is similar to `getsockopt` in POSIX for SO_REUSEPORT + */ +int32_t +__imported_wasi_snapshot_preview1_sock_get_reuse_port(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_reuse_port"))); + +static inline __wasi_errno_t +__wasi_sock_get_reuse_port(__wasi_fd_t fd, int8_t *reuse) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_reuse_port((int32_t)fd, + (int32_t)reuse); +} + +/** + * Retrieve the size of the send buffer + * Note: This is similar to `getsockopt` in POSIX for SO_SNDBUF + */ +int32_t +__imported_wasi_snapshot_preview1_sock_get_send_buf_size(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_send_buf_size"))); + +static inline __wasi_errno_t +__wasi_sock_get_send_buf_size(__wasi_fd_t fd, __wasi_size_t *size) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_send_buf_size((int32_t)fd, + (int32_t)size); +} + +/** + * Listen for connections on a socket + * Note: This is similar to `listen` + */ +int32_t +__imported_wasi_snapshot_preview1_sock_listen(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_listen"))); + +static inline __wasi_errno_t +__wasi_sock_listen(__wasi_fd_t fd, __wasi_size_t backlog) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_listen( + (int32_t)fd, (int32_t)backlog); +} + +/** + * Open a socket + + * The first argument to this function is a handle to an + * address pool. The address pool determines what actions can + * be performed and at which addresses they can be performed to. + + * The address pool cannot be re-assigned. You will need to close + * the socket and open a new one to use a different address pool. + + * Note: This is similar to `socket` in POSIX using PF_INET + */ + +int32_t +__imported_wasi_snapshot_preview1_sock_open(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_open"))); + +static inline __wasi_errno_t +__wasi_sock_open(__wasi_fd_t fd, __wasi_address_family_t af, + __wasi_sock_type_t socktype, __wasi_fd_t *sockfd) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_open( + (int32_t)fd, (int32_t)af, (int32_t)socktype, (int32_t)sockfd); +} + +/** + * Set size of receive buffer + * Note: This is similar to `setsockopt` in POSIX for SO_RCVBUF + */ +int32_t +__imported_wasi_snapshot_preview1_sock_set_recv_buf_size(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_recv_buf_size"))); + +static inline __wasi_errno_t +__wasi_sock_set_recv_buf_size(__wasi_fd_t fd, __wasi_size_t size) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_recv_buf_size((int32_t)fd, + (int32_t)size); +} + +/** + * Enable/disable address reuse on a socket + * Note: This is similar to `setsockopt` in POSIX for SO_REUSEADDR + */ +int32_t +__imported_wasi_snapshot_preview1_sock_set_reuse_addr(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_reuse_addr"))); + +static inline __wasi_errno_t +__wasi_sock_set_reuse_addr(__wasi_fd_t fd, uint8_t reuse) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_reuse_addr((int32_t)fd, + (int32_t)reuse); +} + +/** + * Enable port reuse on a socket + * Note: This is similar to `setsockopt` in POSIX for SO_REUSEPORT + */ +int32_t +__imported_wasi_snapshot_preview1_sock_set_reuse_port(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_reuse_port"))); + +static inline __wasi_errno_t +__wasi_sock_set_reuse_port(__wasi_fd_t fd, uint8_t reuse) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_reuse_port((int32_t)fd, + (int32_t)reuse); +} + +/** + * Set size of send buffer + * Note: This is similar to `setsockopt` in POSIX for SO_SNDBUF + */ +int32_t +__imported_wasi_snapshot_preview1_sock_set_send_buf_size(int32_t arg0) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_send_buf_size"))); + +static inline __wasi_errno_t +__wasi_sock_set_send_buf_size(__wasi_fd_t fd) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_send_buf_size((int32_t)fd); +} + +/** + * TODO: modify recv() and send() + * since don't want to re-compile the wasi-libc, + * we tend to keep original implentations of recv() and send(). + */ +#endif \ No newline at end of file diff --git a/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake b/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake new file mode 100644 index 0000000000..209b0c4c9c --- /dev/null +++ b/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake @@ -0,0 +1,9 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8...3.16) + +project(socket_wasi_ext) + +add_library(${PROJECT_NAME} STATIC ${CMAKE_CURRENT_LIST_DIR}/src/wasi/wasi_socket_ext.c) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/inc/) diff --git a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c new file mode 100644 index 0000000000..9f6bae93e0 --- /dev/null +++ b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include +#include + +#define HANDLE_ERROR(error) \ + if (error != __WASI_ERRNO_SUCCESS) { \ + errno = error; \ + return -1; \ + } + +/* addr_num and port are in network order */ +static void +ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out) +{ + out->kind = IPv4; + out->addr.ip4.port = ntohs(port); + out->addr.ip4.addr.n3 = (addr_num & 0xFF000000) >> 24; + out->addr.ip4.addr.n2 = (addr_num & 0x00FF0000) >> 16; + out->addr.ip4.addr.n1 = (addr_num & 0x0000FF00) >> 8; + out->addr.ip4.addr.n0 = (addr_num & 0x000000FF); +} + +static __wasi_errno_t +sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen, + __wasi_addr_t *wasi_addr) +{ + __wasi_errno_t ret = __WASI_ERRNO_SUCCESS; + if (AF_INET == sock_addr->sa_family) { + assert(sizeof(struct sockaddr_in) == addrlen); + + ipv4_addr_to_wasi_addr( + ((struct sockaddr_in *)sock_addr)->sin_addr.s_addr, + ((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr); + } + else if (AF_INET6 == sock_addr->sa_family) { + // TODO: IPV6 + ret = __WASI_ERRNO_AFNOSUPPORT; + } + else { + ret = __WASI_ERRNO_AFNOSUPPORT; + } + + return ret; +} + +static __wasi_errno_t +sock_addr_remote(__wasi_fd_t fd, struct sockaddr *sock_addr, socklen_t *addrlen) +{ + __wasi_addr_t wasi_addr = { 0 }; + __wasi_errno_t error; + + error = + __wasi_sock_addr_remote(fd, (uint8_t *)&wasi_addr, sizeof(wasi_addr)); + if (__WASI_ERRNO_SUCCESS != error) { + return error; + } + + if (IPv4 == wasi_addr.kind) { + struct sockaddr_in sock_addr_in = { 0 }; + + sock_addr_in.sin_family = AF_INET; + sock_addr_in.sin_addr.s_addr = (wasi_addr.addr.ip4.addr.n3 << 24) + | (wasi_addr.addr.ip4.addr.n2 << 16) + | (wasi_addr.addr.ip4.addr.n1 << 8) + | wasi_addr.addr.ip4.addr.n0; + sock_addr_in.sin_port = htons(wasi_addr.addr.ip4.port); + memcpy(sock_addr, &sock_addr_in, sizeof(sock_addr_in)); + + *addrlen = sizeof(sock_addr_in); + } + else if (IPv6 == wasi_addr.kind) { + // TODO: IPV6 + return __WASI_ERRNO_AFNOSUPPORT; + } + else { + return __WASI_ERRNO_AFNOSUPPORT; + } + + return __WASI_ERRNO_SUCCESS; +} + +int +accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + __wasi_addr_t wasi_addr = { 0 }; + __wasi_fd_t new_sockfd; + __wasi_errno_t error; + + error = __wasi_sock_accept(sockfd, &new_sockfd); + HANDLE_ERROR(error) + + // error = sock_addr_remote(new_sockfd, addr, addrlen); + // HANDLE_ERROR(error) + *addrlen = 0; + + return new_sockfd; +} + +int +bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + __wasi_addr_t wasi_addr = { 0 }; + __wasi_errno_t error; + + error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr); + HANDLE_ERROR(error) + + error = __wasi_sock_bind(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} + +int +connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + __wasi_addr_t wasi_addr = { 0 }; + __wasi_errno_t error; + + error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr); + HANDLE_ERROR(error) + + error = __wasi_sock_connect(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} + +int +listen(int sockfd, int backlog) +{ + __wasi_errno_t error = __wasi_sock_listen(sockfd, backlog); + HANDLE_ERROR(error) + return __WASI_ERRNO_SUCCESS; +} + +int +socket(int domain, int type, int protocol) +{ + // the stub of address pool fd + __wasi_fd_t poolfd = -1; + __wasi_fd_t sockfd; + __wasi_errno_t error; + __wasi_address_family_t af; + __wasi_sock_type_t socktype; + + if (AF_INET == domain) { + af = INET4; + } + else if (AF_INET6 == domain) { + af = INET6; + } + else { + return __WASI_ERRNO_NOPROTOOPT; + } + + if (SOCK_DGRAM == type) { + socktype = SOCKET_DGRAM; + } + else if (SOCK_STREAM == type) { + socktype = SOCKET_STREAM; + } + else { + return __WASI_ERRNO_NOPROTOOPT; + } + + error = __wasi_sock_open(poolfd, af, socktype, &sockfd); + HANDLE_ERROR(error) + + return sockfd; +} diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index a8ecb234d2..733cd4374c 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -50,6 +50,7 @@ typedef struct WASIContext { struct fd_table *curfds; struct fd_prestats *prestats; struct argv_environ_values *argv_environ; + struct addr_pool *addr_pool; char *argv_buf; char **argv_list; char *env_buf; @@ -83,6 +84,14 @@ wasi_ctx_get_prestats(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) return wasi_ctx->prestats; } +static inline struct addr_pool * +wasi_ctx_get_addr_pool(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) +{ + if (!wasi_ctx) + return NULL; + return wasi_ctx->addr_pool; +} + static wasi_errno_t wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf) { @@ -986,113 +995,278 @@ wasi_random_get(wasm_exec_env_t exec_env, void *buf, uint32 buf_len) return wasmtime_ssp_random_get(buf, buf_len); } +static wasi_errno_t +wasi_sock_accept(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_fd_t *fd_new) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_accept(curfds, fd, fd_new); +} + +static wasi_errno_t +wasi_sock_addr_local(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *buf, + wasi_size_t buf_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_addr_local(curfds, fd, buf, buf_len); +} + +static wasi_errno_t +wasi_sock_addr_remote(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *buf, + wasi_size_t buf_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_addr_remote(curfds, fd, buf, buf_len); +} + +static wasi_errno_t +wasi_sock_addr_resolve(wasm_exec_env_t exec_env, wasi_fd_t fd, const char *host, + wasi_ip_port_t port, uint8 *buf, wasi_size_t size) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_bind(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_addr_t *addr) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + struct addr_pool *addr_pool = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx); + + return wasi_ssp_sock_bind(curfds, addr_pool, fd, addr); +} + +static wasi_errno_t +wasi_sock_close(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_addr_t *addr) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + struct addr_pool *addr_pool = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx); + + return wasi_ssp_sock_connect(curfds, addr_pool, fd, addr); +} + +static wasi_errno_t +wasi_sock_get_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_size_t *size) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_get_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_get_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_get_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_size_t *size) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_listen(wasm_exec_env_t exec_env, wasi_fd_t fd, uint32 backlog) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_listen(curfds, fd, backlog); +} + +static wasi_errno_t +wasi_sock_open(wasm_exec_env_t exec_env, wasi_fd_t poolfd, + wasi_address_family_t af, wasi_sock_type_t socktype, + wasi_fd_t *sockfd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_open(curfds, poolfd, af, socktype, sockfd); +} + +static wasi_errno_t +wasi_sock_set_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_size_t size) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_set_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_set_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_set_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_size_t size) +{ + return __WASI_ENOSYS; +} + static wasi_errno_t wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, - uint32 ri_data_len, wasi_riflags_t ri_flags, - uint32 *ro_datalen_app, wasi_roflags_t *ro_flags) + uint32 ri_data_len, wasi_riflags_t ri_flags, uint32 *ro_data_len, + wasi_roflags_t *ro_flags) { + /** + * ri_data_len is the length of a list of iovec_app_t, which head is + * ri_data. ro_data_len is the number of bytes received + **/ wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - wasi_iovec_t *iovec, *iovec_begin; uint64 total_size; - size_t ro_datalen; uint32 i; wasi_errno_t err; if (!wasi_ctx) - return (wasi_errno_t)-1; + return __WASI_EINVAL; total_size = sizeof(iovec_app_t) * (uint64)ri_data_len; - if (!validate_native_addr(ro_datalen_app, (uint32)sizeof(uint32)) + if (!validate_native_addr(ro_data_len, (uint32)sizeof(uint32)) || !validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t)) || total_size >= UINT32_MAX || !validate_native_addr(ri_data, (uint32)total_size)) - return (wasi_errno_t)-1; - - total_size = sizeof(wasi_iovec_t) * (uint64)ri_data_len; - if (total_size >= UINT32_MAX - || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) - return (wasi_errno_t)-1; + return __WASI_EINVAL; - iovec = iovec_begin; + /* recv ri_data one by one */ + *ro_data_len = 0; + for (i = 0; i < ri_data_len; ri_data++, i++) { + void *buf; + size_t bytes_recv; - for (i = 0; i < ri_data_len; i++, ri_data++, iovec++) { if (!validate_app_addr(ri_data->buf_offset, ri_data->buf_len)) { - err = (wasi_errno_t)-1; - goto fail; + return __WASI_EINVAL; } - iovec->buf = (void *)addr_app_to_native(ri_data->buf_offset); - iovec->buf_len = ri_data->buf_len; - } - - err = wasmtime_ssp_sock_recv(curfds, sock, iovec_begin, ri_data_len, - ri_flags, &ro_datalen, ro_flags); - if (err) - goto fail; - - *(uint32 *)ro_datalen_app = (uint32)ro_datalen; - /* success */ - err = 0; + buf = (void *)addr_app_to_native(ri_data->buf_offset); + err = wasmtime_ssp_sock_recv(curfds, sock, buf, ri_data->buf_len, + &bytes_recv); + if (err != __WASI_ESUCCESS) { + return err; + } + *ro_data_len += bytes_recv; + } -fail: - wasm_runtime_free(iovec_begin); - return err; + *ro_flags = ri_flags; + return __WASI_ESUCCESS; } static wasi_errno_t wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock, const iovec_app_t *si_data, uint32 si_data_len, - wasi_siflags_t si_flags, uint32 *so_datalen_app) + wasi_siflags_t si_flags, uint32 *so_data_len) { + /** + * si_data_len is the length of a list of iovec_app_t, which head is + * si_data. so_data_len is the number of bytes sent + **/ wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - wasi_ciovec_t *ciovec, *ciovec_begin; uint64 total_size; - size_t so_datalen; uint32 i; wasi_errno_t err; if (!wasi_ctx) - return (wasi_errno_t)-1; + return __WASI_EINVAL; total_size = sizeof(iovec_app_t) * (uint64)si_data_len; - if (!validate_native_addr(so_datalen_app, sizeof(uint32)) + if (!validate_native_addr(so_data_len, sizeof(uint32)) || total_size >= UINT32_MAX || !validate_native_addr((void *)si_data, (uint32)total_size)) - return (wasi_errno_t)-1; + return __WASI_EINVAL; - total_size = sizeof(wasi_ciovec_t) * (uint64)si_data_len; - if (total_size >= UINT32_MAX - || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) - return (wasi_errno_t)-1; - - ciovec = ciovec_begin; + /* send si_data one by one */ + *so_data_len = 0; + for (i = 0; i < si_data_len; i++, si_data++) { + void *buf; + size_t bytes_sent; - for (i = 0; i < si_data_len; i++, si_data++, ciovec++) { if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) { - err = (wasi_errno_t)-1; - goto fail; + return __WASI_EINVAL; } - ciovec->buf = (char *)addr_app_to_native(si_data->buf_offset); - ciovec->buf_len = si_data->buf_len; - } - - err = wasmtime_ssp_sock_send(curfds, sock, ciovec_begin, si_data_len, - si_flags, &so_datalen); - if (err) - goto fail; - - *so_datalen_app = (uint32)so_datalen; - /* success */ - err = 0; + buf = (void *)addr_app_to_native(si_data->buf_offset); + err = wasmtime_ssp_sock_send(curfds, sock, buf, si_data->buf_len, + &bytes_sent); + if (err != __WASI_ESUCCESS) { + return err; + } + *so_data_len += bytes_sent; + } -fail: - wasm_runtime_free(ciovec_begin); - return err; + return __WASI_ESUCCESS; } static wasi_errno_t @@ -1103,9 +1277,9 @@ wasi_sock_shutdown(wasm_exec_env_t exec_env, wasi_fd_t sock, wasi_sdflags_t how) struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); if (!wasi_ctx) - return (wasi_errno_t)-1; + return __WASI_EINVAL; - return wasmtime_ssp_sock_shutdown(curfds, sock, how); + return wasmtime_ssp_sock_shutdown(curfds, sock); } static wasi_errno_t @@ -1161,8 +1335,25 @@ static NativeSymbol native_symbols_libc_wasi[] = { REG_NATIVE_FUNC(proc_exit, "(i)"), REG_NATIVE_FUNC(proc_raise, "(i)i"), REG_NATIVE_FUNC(random_get, "(*~)i"), + REG_NATIVE_FUNC(sock_accept, "(i*)i"), + REG_NATIVE_FUNC(sock_addr_local, "(i*i)i"), + REG_NATIVE_FUNC(sock_addr_remote, "(i*i)i"), + REG_NATIVE_FUNC(sock_addr_resolve, "(i*i*i)i"), + REG_NATIVE_FUNC(sock_bind, "(i*)i"), + REG_NATIVE_FUNC(sock_close, "(i)i"), + REG_NATIVE_FUNC(sock_connect, "(i*)i"), + REG_NATIVE_FUNC(sock_get_recv_buf_size, "(i*)i"), + REG_NATIVE_FUNC(sock_get_reuse_addr, "(i*)i"), + REG_NATIVE_FUNC(sock_get_reuse_port, "(i*)i"), + REG_NATIVE_FUNC(sock_get_send_buf_size, "(i*)i"), + REG_NATIVE_FUNC(sock_listen, "(ii)i"), + REG_NATIVE_FUNC(sock_open, "(iii*)i"), REG_NATIVE_FUNC(sock_recv, "(i*ii**)i"), REG_NATIVE_FUNC(sock_send, "(i*ii*)i"), + REG_NATIVE_FUNC(sock_set_recv_buf_size, "(ii)i"), + REG_NATIVE_FUNC(sock_set_reuse_addr, "(ii)i"), + REG_NATIVE_FUNC(sock_set_reuse_port, "(ii)i"), + REG_NATIVE_FUNC(sock_set_send_buf_size, "(ii)i"), REG_NATIVE_FUNC(sock_shutdown, "(ii)i"), REG_NATIVE_FUNC(sched_yield, "()i"), }; diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h index b57f8835e7..be509576b0 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h @@ -13,38 +13,43 @@ extern "C" { #endif +typedef __wasi_address_family_t wasi_address_family_t; +typedef __wasi_addr_t wasi_addr_t; +typedef __wasi_advice_t wasi_advice_t; +typedef __wasi_ciovec_t wasi_ciovec_t; +typedef __wasi_clockid_t wasi_clockid_t; +typedef __wasi_dircookie_t wasi_dircookie_t; typedef __wasi_errno_t wasi_errno_t; +typedef __wasi_event_t wasi_event_t; +typedef __wasi_exitcode_t wasi_exitcode_t; +typedef __wasi_fdflags_t wasi_fdflags_t; +typedef __wasi_fdstat_t wasi_fdstat_t; typedef __wasi_fd_t wasi_fd_t; -typedef __wasi_clockid_t wasi_clockid_t; -typedef __wasi_timestamp_t wasi_timestamp_t; -typedef __wasi_prestat_t wasi_prestat_t; -typedef __wasi_iovec_t wasi_iovec_t; -typedef __wasi_ciovec_t wasi_ciovec_t; -typedef __wasi_filetype_t wasi_filetype_t; -typedef __wasi_filesize_t wasi_filesize_t; typedef __wasi_filedelta_t wasi_filedelta_t; -typedef __wasi_whence_t wasi_whence_t; -typedef __wasi_fdstat_t wasi_fdstat_t; -typedef __wasi_fdflags_t wasi_fdflags_t; -typedef __wasi_rights_t wasi_rights_t; -typedef __wasi_advice_t wasi_advice_t; -typedef __wasi_lookupflags_t wasi_lookupflags_t; -typedef __wasi_oflags_t wasi_oflags_t; -typedef __wasi_dircookie_t wasi_dircookie_t; +typedef __wasi_filesize_t wasi_filesize_t; typedef __wasi_filestat_t wasi_filestat_t; +typedef __wasi_filetype_t wasi_filetype_t; typedef __wasi_fstflags_t wasi_fstflags_t; -typedef __wasi_subscription_t wasi_subscription_t; -typedef __wasi_event_t wasi_event_t; -typedef __wasi_exitcode_t wasi_exitcode_t; -typedef __wasi_signal_t wasi_signal_t; +typedef __wasi_iovec_t wasi_iovec_t; +typedef __wasi_ip_port_t wasi_ip_port_t; +typedef __wasi_lookupflags_t wasi_lookupflags_t; +typedef __wasi_oflags_t wasi_oflags_t; +typedef __wasi_preopentype_t wasi_preopentype_t; +typedef __wasi_prestat_t wasi_prestat_t; typedef __wasi_riflags_t wasi_riflags_t; +typedef __wasi_rights_t wasi_rights_t; typedef __wasi_roflags_t wasi_roflags_t; -typedef __wasi_siflags_t wasi_siflags_t; typedef __wasi_sdflags_t wasi_sdflags_t; -typedef __wasi_preopentype_t wasi_preopentype_t; +typedef __wasi_siflags_t wasi_siflags_t; +typedef __wasi_signal_t wasi_signal_t; +typedef __wasi_size_t wasi_size_t; +typedef __wasi_sock_type_t wasi_sock_type_t; +typedef __wasi_subscription_t wasi_subscription_t; +typedef __wasi_timestamp_t wasi_timestamp_t; +typedef __wasi_whence_t wasi_whence_t; #ifdef __cplusplus } #endif -#endif /* end of _LIBC_WASI_WRAPPER_H */ +#endif /* end of _LIBC_WASI_WRAPPER_H */ \ No newline at end of file diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index 560fdeb009..8c9d265a73 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -49,6 +49,9 @@ _Static_assert(_Alignof(int64_t) == 8, "non-wasi data layout"); _Static_assert(_Alignof(uint64_t) == 8, "non-wasi data layout"); #endif +typedef uint32_t __wasi_size_t; +_Static_assert(_Alignof(__wasi_size_t) == 4, "non-wasi data layout"); + typedef uint8_t __wasi_advice_t; #define __WASI_ADVICE_NORMAL (0) #define __WASI_ADVICE_SEQUENTIAL (1) @@ -211,35 +214,44 @@ typedef uint64_t __wasi_rights_t; * Observe that WASI defines rights in the plural form * TODO: refactor to use RIGHTS instead of RIGHT */ -#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(1 << 0)) -#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(1 << 1)) -#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(1 << 2)) -#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(1 << 3)) -#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(1 << 4)) -#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(1 << 5)) -#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(1 << 6)) -#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(1 << 7)) -#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(1 << 8)) -#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(1 << 9)) -#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(1 << 10)) -#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(1 << 11)) -#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(1 << 12)) -#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(1 << 13)) -#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(1 << 14)) -#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(1 << 15)) -#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(1 << 16)) -#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(1 << 17)) -#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(1 << 18)) -#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(1 << 19)) -#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(1 << 20)) -#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(1 << 21)) -#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(1 << 22)) -#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(1 << 23)) -#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(1 << 24)) -#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(1 << 25)) -#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(1 << 26)) -#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(1 << 27)) -#define __WASI_RIGHT_SOCK_SHUTDOWN ((__wasi_rights_t)(1 << 28)) +#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(UINT64_C(1) << 0)) +#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(UINT64_C(1) << 1)) +#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(UINT64_C(1) << 2)) +#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(UINT64_C(1) << 3)) +#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(UINT64_C(1) << 4)) +#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(UINT64_C(1) << 5)) +#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(UINT64_C(1) << 6)) +#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(UINT64_C(1) << 7)) +#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(UINT64_C(1) << 8)) +#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 9)) +#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(UINT64_C(1) << 10)) +#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 11)) +#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(UINT64_C(1) << 12)) +#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(UINT64_C(1) << 13)) +#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(UINT64_C(1) << 14)) +#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(UINT64_C(1) << 15)) +#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 16)) +#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(UINT64_C(1) << 17)) +#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 18)) +#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 19)) +#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 20)) +#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 21)) +#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 22)) +#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 23)) +#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(UINT64_C(1) << 24)) +#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 25)) +#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(UINT64_C(1) << 26)) +#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(UINT64_C(1) << 27)) +#define __WASI_RIGHT_SOCK_CONNECT ((__wasi_rights_t)(UINT64_C(1) << 28)) +#define __WASI_RIGHT_SOCK_LISTEN ((__wasi_rights_t)(UINT64_C(1) << 29)) +#define __WASI_RIGHT_SOCK_BIND ((__wasi_rights_t)(UINT64_C(1) << 30)) +#define __WASI_RIGHT_SOCK_ACCEPT ((__wasi_rights_t)(UINT64_C(1) << 31)) +#define __WASI_RIGHT_SOCK_RECV ((__wasi_rights_t)(UINT64_C(1) << 32)) +#define __WASI_RIGHT_SOCK_SEND ((__wasi_rights_t)(UINT64_C(1) << 33)) +#define __WASI_RIGHT_SOCK_ADDR_LOCAL ((__wasi_rights_t)(UINT64_C(1) << 34)) +#define __WASI_RIGHT_SOCK_ADDR_REMOTE ((__wasi_rights_t)(UINT64_C(1) << 35)) +#define __WASI_RIGHT_SOCK_RECV_FROM ((__wasi_rights_t)(UINT64_C(1) << 36)) +#define __WASI_RIGHT_SOCK_SEND_TO ((__wasi_rights_t)(UINT64_C(1) << 37)) typedef uint16_t __wasi_roflags_t; #define __WASI_SOCK_RECV_DATA_TRUNCATED (0x0001) @@ -301,6 +313,7 @@ typedef uint8_t __wasi_preopentype_t; struct fd_table; struct fd_prestats; struct argv_environ_values; +struct addr_pool; typedef struct __wasi_dirent_t { __wasi_dircookie_t d_next; @@ -536,6 +549,55 @@ _Static_assert(_Alignof(__wasi_subscription_t) == 8, "witx calculated align"); _Static_assert(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset"); _Static_assert(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset"); +/* keep syncing with wasi_socket_ext.h */ +typedef enum { + SOCKET_DGRAM = 0, + SOCKET_STREAM, +} __wasi_sock_type_t; + +typedef uint16_t __wasi_ip_port_t; + +typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t; + +/* n0.n1.n2.n3 */ +typedef struct __wasi_addr_ip4_t { + uint8_t n0; + uint8_t n1; + uint8_t n2; + uint8_t n3; +} __wasi_addr_ip4_t; + +typedef struct __wasi_addr_ip4_port_t { + __wasi_addr_ip4_t addr; + __wasi_ip_port_t port; +} __wasi_addr_ip4_port_t; + +typedef struct __wasi_addr_ip6_t { + uint16_t n0; + uint16_t n1; + uint16_t n2; + uint16_t n3; + uint16_t h0; + uint16_t h1; + uint16_t h2; + uint16_t h3; +} __wasi_addr_ip6_t; + +typedef struct __wasi_addr_ip6_port_t { + __wasi_addr_ip6_t addr; + __wasi_ip_port_t port; +} __wasi_addr_ip6_port_t; + +typedef struct __wasi_addr_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_port_t ip4; + __wasi_addr_ip6_port_t ip6; + } addr; +} __wasi_addr_t; + +typedef enum { INET4 = 0, INET6 } __wasi_address_family_t; + #if defined(WASMTIME_SSP_WASI_API) #define WASMTIME_SSP_SYSCALL_NAME(name) \ asm("__wasi_" #name) @@ -920,16 +982,71 @@ __wasi_errno_t wasmtime_ssp_random_get( size_t buf_len ) WASMTIME_SSP_SYSCALL_NAME(random_get) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_accept( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_fd_t *fd_new +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_addr_local( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_addr_remote( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_open( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t poolfd, __wasi_address_family_t af, __wasi_sock_type_t socktype, + __wasi_fd_t *sockfd +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_bind( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_connect( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_listen( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t backlog +) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasmtime_ssp_sock_recv( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif __wasi_fd_t sock, - const __wasi_iovec_t *ri_data, - size_t ri_data_len, - __wasi_riflags_t ri_flags, - size_t *ro_datalen, - __wasi_roflags_t *ro_flags + void *buf, + size_t buf_len, + size_t *recv_len ) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_send( @@ -937,18 +1054,16 @@ __wasi_errno_t wasmtime_ssp_sock_send( struct fd_table *curfds, #endif __wasi_fd_t sock, - const __wasi_ciovec_t *si_data, - size_t si_data_len, - __wasi_siflags_t si_flags, - size_t *so_datalen + const void *buf, + size_t buf_len, + size_t *sent_len ) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_shutdown( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t sock, - __wasi_sdflags_t how + __wasi_fd_t sock ) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sched_yield(void) diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 7e01f85ca8..7eff817e68 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -60,6 +60,7 @@ static_assert(sizeof(struct iovec) == sizeof(__wasi_ciovec_t), static __thread struct fd_table *curfds; static __thread struct fd_prestats *prestats; static __thread struct argv_environ_values *argv_environ; +static __thread struct addr_pool *addr_pool; #endif // Converts a POSIX error code to a CloudABI error code. @@ -2716,113 +2717,294 @@ wasmtime_ssp_random_get(void *buf, size_t nbyte) } __wasi_errno_t -wasmtime_ssp_sock_recv( +wasi_ssp_sock_accept( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t sock, const __wasi_iovec_t *ri_data, size_t ri_data_len, - __wasi_riflags_t ri_flags, size_t *ro_datalen, __wasi_roflags_t *ro_flags) + __wasi_fd_t fd, __wasi_fd_t *fd_new) { - // Convert input to msghdr. - struct msghdr hdr = { - .msg_iov = (struct iovec *)ri_data, - .msg_iovlen = ri_data_len, - }; - int nflags = 0; - if ((ri_flags & __WASI_SOCK_RECV_PEEK) != 0) - nflags |= MSG_PEEK; - if ((ri_flags & __WASI_SOCK_RECV_WAITALL) != 0) - nflags |= MSG_WAITALL; - + __wasi_filetype_t wasi_type; + __wasi_rights_t max_base, max_inheriting; struct fd_object *fo; + bh_socket_t new_sock; + int ret; __wasi_errno_t error = - fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0); - if (error != 0) { + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ACCEPT, 0); + if (error != __WASI_ESUCCESS) return error; - } - ssize_t datalen = recvmsg(fd_number(fo), &hdr, nflags); + ret = os_socket_accept(fd_number(fo), &new_sock, NULL, NULL); fd_object_release(fo); - if (datalen < 0) { + if (ret == BHT_ERROR) return convert_errno(errno); + + error = fd_determine_type_rights(new_sock, &wasi_type, &max_base, + &max_inheriting); + if (error != __WASI_ESUCCESS) { + os_socket_close(ret); + return error; } - // Convert msghdr to output. - *ro_datalen = (size_t)datalen; - *ro_flags = 0; - if ((hdr.msg_flags & MSG_TRUNC) != 0) - *ro_flags |= __WASI_SOCK_RECV_DATA_TRUNCATED; - return 0; + error = fd_table_insert_fd(curfds, new_sock, wasi_type, max_base, + max_inheriting, fd_new); + if (error != __WASI_ESUCCESS) { + os_socket_close(ret); + return error; + } + + return __WASI_ESUCCESS; } __wasi_errno_t -wasmtime_ssp_sock_send( +wasi_ssp_sock_addr_local( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t sock, const __wasi_ciovec_t *si_data, size_t si_data_len, - __wasi_siflags_t si_flags, size_t *so_datalen) NO_LOCK_ANALYSIS + __wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len) { - // Convert input to msghdr. - struct msghdr hdr = { - .msg_iov = (struct iovec *)si_data, - .msg_iovlen = si_data_len, - }; + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0); + if (error != __WASI_ESUCCESS) + return error; + + fd_object_release(fo); + return __WASI_ENOSYS; +} + +__wasi_errno_t +wasi_ssp_sock_addr_remote( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_REMOTE, 0); + if (error != __WASI_ESUCCESS) + return error; + + fd_object_release(fo); + return __WASI_ENOSYS; +} + +__wasi_errno_t +wasi_ssp_sock_bind( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr) +{ + char buf[24] = { 0 }; + const char *format = "%u.%u.%u.%u"; + struct fd_object *fo; + __wasi_errno_t error; + int port = addr->addr.ip4.port; + int ret; + + snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1, + addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3); + + if (!addr_pool_search(addr_pool, buf)) { + return __WASI_EACCES; + } + + error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_BIND, 0); + if (error != __WASI_ESUCCESS) + return error; + + ret = os_socket_bind(fd_number(fo), buf, &port); + fd_object_release(fo); + if (ret == BHT_ERROR) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} - // Attach file descriptors if present. +__wasi_errno_t +wasi_ssp_sock_connect( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr) +{ + char buf[24] = { 0 }; + const char *format = "%u.%u.%u.%u"; + struct fd_object *fo; __wasi_errno_t error; + int ret; + + snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1, + addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3); - // Send message. + if (!addr_pool_search(addr_pool, buf)) { + return __WASI_EACCES; + } + + error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_BIND, 0); + if (error != __WASI_ESUCCESS) + return error; + + ret = os_socket_connect(fd_number(fo), buf, addr->addr.ip4.port); + fd_object_release(fo); + if (ret == BHT_ERROR) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_listen( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t backlog) +{ struct fd_object *fo; - error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0); - if (error != 0) - goto out; - ssize_t len = sendmsg(fd_number(fo), &hdr, 0); + int ret; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_LISTEN, 0); + if (error != __WASI_ESUCCESS) + return error; + + ret = os_socket_listen(fd_number(fo), backlog); fd_object_release(fo); - if (len < 0) { - error = convert_errno(errno); + if (ret == BHT_ERROR) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_open( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t poolfd, __wasi_address_family_t af, __wasi_sock_type_t socktype, + __wasi_fd_t *sockfd) +{ + bh_socket_t sock; + int tcp_or_udp = 0; + int ret; + __wasi_filetype_t wasi_type; + __wasi_rights_t max_base, max_inheriting; + __wasi_errno_t error; + + (void)poolfd; + + if (INET4 != af) { + return __WASI_EAFNOSUPPORT; + } + + tcp_or_udp = SOCKET_DGRAM == socktype ? 0 : 1; + + ret = os_socket_create(&sock, tcp_or_udp); + if (ret == BHT_ERROR) { + return convert_errno(errno); + } + + error = + fd_determine_type_rights(sock, &wasi_type, &max_base, &max_inheriting); + if (error != __WASI_ESUCCESS) { + os_socket_close(ret); + return error; + } + + if (SOCKET_DGRAM == socktype) { + assert(wasi_type == __WASI_FILETYPE_SOCKET_DGRAM); } else { - *so_datalen = (size_t)len; + assert(wasi_type == __WASI_FILETYPE_SOCKET_STREAM); } -out: - return error; + // TODO: base rights and inheriting rights ? + error = fd_table_insert_fd(curfds, sock, wasi_type, max_base, + max_inheriting, sockfd); + if (error != __WASI_ESUCCESS) { + os_socket_close(ret); + return error; + } + + return __WASI_ESUCCESS; } __wasi_errno_t -wasmtime_ssp_sock_shutdown( +wasmtime_ssp_sock_recv( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t sock, __wasi_sdflags_t how) + __wasi_fd_t sock, void *buf, size_t buf_len, size_t *recv_len) { - int nhow; - switch (how) { - case __WASI_SHUT_RD: - nhow = SHUT_RD; - break; - case __WASI_SHUT_WR: - nhow = SHUT_WR; - break; - case __WASI_SHUT_RD | __WASI_SHUT_WR: - nhow = SHUT_RDWR; - break; - default: - return __WASI_EINVAL; + struct fd_object *fo; + __wasi_errno_t error; + int ret; + + error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0); + if (error != 0) { + return error; } + ret = os_socket_recv(fd_number(fo), buf, buf_len); + fd_object_release(fo); + if (ret == BHT_ERROR) { + return convert_errno(errno); + } + + *recv_len = (size_t)ret; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_send( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, const void *buf, size_t buf_len, size_t *sent_len) +{ struct fd_object *fo; - __wasi_errno_t error = - fd_object_get(curfds, &fo, sock, __WASI_RIGHT_SOCK_SHUTDOWN, 0); + __wasi_errno_t error; + int ret; + + error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) { + return error; + } + + ret = os_socket_send(fd_number(fo), buf, buf_len); + fd_object_release(fo); + if (ret == BHT_ERROR) { + return convert_errno(errno); + } + + *sent_len = (size_t)ret; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_shutdown( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + + error = fd_object_get(curfds, &fo, sock, 0, 0); if (error != 0) return error; - int ret = shutdown(fd_number(fo), nhow); + ret = os_socket_shutdown(fd_number(fo)); fd_object_release(fo); - if (ret < 0) + if (ret == BHT_ERROR) return convert_errno(errno); - return 0; + + return __WASI_ESUCCESS; } __wasi_errno_t @@ -2943,3 +3125,88 @@ fd_prestats_destroy(struct fd_prestats *pt) wasm_runtime_free(pt->prestats); } } + +bool +addr_pool_init(struct addr_pool *addr_pool) +{ + addr_pool->next = NULL; + addr_pool->addr = 0; + addr_pool->mask = 0; + return true; +} + +bool +addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask) +{ + struct addr_pool *cur = addr_pool; + struct addr_pool *next; + + if (!addr_pool) { + return false; + } + + if (!(next = wasm_runtime_malloc(sizeof(struct addr_pool)))) { + return false; + } + + next->next = NULL; + next->mask = mask; + if (os_socket_inet_network(addr, &next->addr) != BHT_OK) { + wasm_runtime_free(next); + return false; + } + + /* attach with */ + while (cur->next) { + cur = cur->next; + } + cur->next = next; + return true; +} + +static bool +compare_address(const struct addr_pool *addr_pool_entry, const char *addr) +{ + /* host order */ + uint32 target; + uint32 address = addr_pool_entry->addr; + /* 0.0.0.0 means any address */ + if (0 == address) { + return true; + } + + if (os_socket_inet_network(addr, &target) != BHT_OK) { + return false; + } + + uint32 mask = addr_pool_entry->mask; + uint32 first_address = address & mask; + uint32 last_address = address | (~mask); + return first_address <= target && target <= last_address; +} + +bool +addr_pool_search(struct addr_pool *addr_pool, const char *addr) +{ + struct addr_pool *cur = addr_pool->next; + + while (cur) { + if (compare_address(cur, addr)) + return true; + cur = cur->next; + } + + return false; +} + +void +addr_pool_destroy(struct addr_pool *addr_pool) +{ + struct addr_pool *cur = addr_pool->next; + + while (cur) { + struct addr_pool *next = cur->next; + wasm_runtime_free(cur); + cur = next; + } +} diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h index 62214dc2fa..ad124c8228 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h @@ -46,6 +46,13 @@ struct argv_environ_values { size_t environ_count; }; +struct addr_pool { + struct addr_pool *next; + /* addr and mask in host order */ + uint32 addr; + uint8 mask; +}; + bool fd_table_init(struct fd_table *); bool @@ -66,4 +73,13 @@ fd_table_destroy(struct fd_table *ft); void fd_prestats_destroy(struct fd_prestats *pt); +bool +addr_pool_init(struct addr_pool *); +bool +addr_pool_insert(struct addr_pool *, const char *, uint8 mask); +bool +addr_pool_search(struct addr_pool *, const char *); +void +addr_pool_destroy(struct addr_pool *); + #endif diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h index 434561dcbf..4f58381598 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h @@ -32,7 +32,13 @@ __WASI_RIGHT_FD_FILESTAT_SET_SIZE | \ __WASI_RIGHT_PATH_SYMLINK | __WASI_RIGHT_PATH_UNLINK_FILE | \ __WASI_RIGHT_PATH_REMOVE_DIRECTORY | \ - __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_SHUTDOWN) + __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_CONNECT | \ + __WASI_RIGHT_SOCK_LISTEN | __WASI_RIGHT_SOCK_BIND | \ + __WASI_RIGHT_SOCK_ACCEPT | __WASI_RIGHT_SOCK_RECV | \ + __WASI_RIGHT_SOCK_SEND | __WASI_RIGHT_SOCK_ADDR_LOCAL | \ + __WASI_RIGHT_SOCK_ADDR_REMOTE | __WASI_RIGHT_SOCK_RECV_FROM | \ + __WASI_RIGHT_SOCK_SEND_TO) + // Block and character device interaction is outside the scope of // CloudABI. Simply allow everything. @@ -71,10 +77,15 @@ #define RIGHTS_REGULAR_FILE_INHERITING 0 // Operations that apply to sockets and socket pairs. -#define RIGHTS_SOCKET_BASE \ - (__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ - __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_FILESTAT_GET | \ - __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_SHUTDOWN) +#define RIGHTS_SOCKET_BASE \ + (__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_FILESTAT_GET | \ + __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_CONNECT | \ + __WASI_RIGHT_SOCK_LISTEN | __WASI_RIGHT_SOCK_BIND | \ + __WASI_RIGHT_SOCK_ACCEPT | __WASI_RIGHT_SOCK_RECV | \ + __WASI_RIGHT_SOCK_SEND | __WASI_RIGHT_SOCK_ADDR_LOCAL | \ + __WASI_RIGHT_SOCK_ADDR_REMOTE | __WASI_RIGHT_SOCK_RECV_FROM | \ + __WASI_RIGHT_SOCK_SEND_TO) #define RIGHTS_SOCKET_INHERITING RIGHTS_ALL // Operations that apply to TTYs. diff --git a/core/shared/platform/common/posix/posix_socket.c b/core/shared/platform/common/posix/posix_socket.c index 6492724622..f4bb2e6357 100644 --- a/core/shared/platform/common/posix/posix_socket.c +++ b/core/shared/platform/common/posix/posix_socket.c @@ -8,6 +8,16 @@ #include +static void +textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out) +{ + assert(textual); + + out->sin_family = AF_INET; + out->sin_port = htons(port); + out->sin_addr.s_addr = inet_addr(textual); +} + int os_socket_create(bh_socket_t *sock, int tcp_or_udp) { @@ -97,6 +107,23 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, return BHT_OK; } +int +os_socket_connect(bh_socket_t socket, const char *addr, int port) +{ + struct sockaddr_in addr_in = { 0 }; + socklen_t addr_len = sizeof(struct sockaddr_in); + int ret = 0; + + textual_addr_to_sockaddr(addr, port, &addr_in); + + ret = connect(socket, (struct sockaddr *)&addr_in, addr_len); + if (ret == -1) { + return BHT_ERROR; + } + + return BHT_OK; +} + int os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) { @@ -122,3 +149,13 @@ os_socket_shutdown(bh_socket_t socket) shutdown(socket, O_RDWR); return BHT_OK; } + +int +os_socket_inet_network(const char *cp, uint32 *out) +{ + if (!cp) + return BHT_ERROR; + + *out = inet_network(cp); + return BHT_OK; +} \ No newline at end of file diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index 5a7e825cb8..9d9e20ac41 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -244,6 +244,17 @@ int os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, unsigned int *addrlen); +/** + * initiate a connection on a socket + * + * @param socket the socket to connect with + * @param addr the ip address, only IPv4 supported currently + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_connect(bh_socket_t socket, const char *addr, int port); + /** * Blocking receive message from a socket. * @@ -289,6 +300,18 @@ os_socket_close(bh_socket_t socket); int os_socket_shutdown(bh_socket_t socket); +/** + * converts cp into a number in host byte order suitable for use as + * an Internet network address + * + * @param cp a string in IPv4 numbers-and-dots notation + * + * @return On success, the converted address is returned. + * If the input is invalid, -1 is returned + */ +int +os_socket_inet_network(const char *cp, uint32 *out); + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/linux-sgx/sgx_socket.c b/core/shared/platform/linux-sgx/sgx_socket.c index e9a824fda6..9ed92f53ef 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.c +++ b/core/shared/platform/linux-sgx/sgx_socket.c @@ -227,4 +227,72 @@ shutdown(int sockfd, int how) return ret; } +int +os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, + unsigned int *addrlen) + +{ + errno = ENOSYS; + return -1; +} +int +os_socket_bind(bh_socket_t socket, const char *host, int *port) +{ + errno = ENOSYS; + return -1; +} + +int +os_socket_close(bh_socket_t socket) +{ + errno = ENOSYS; + return -1; +} + +int +os_socket_connect(bh_socket_t socket, const char *addr, int port) +{} + +int +os_socket_create(bh_socket_t *sock, int tcp_or_udp) +{ + errno = ENOSYS; + return -1; +} + +int +os_socket_inet_network(const char *cp, uint32 *out) +{ + errno = ENOSYS; + return -1; +} + +int +os_socket_listen(bh_socket_t socket, int max_client) +{ + errno = ENOSYS; + return -1; +} + +int +os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) +{ + errno = ENOSYS; + return -1; +} + +int +os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) +{ + errno = ENOSYS; + return -1; +} + +int +os_socket_shutdown(bh_socket_t socket) +{ + errno = ENOSYS; + return -1; +} + #endif diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index 0057aeeda5..cff27a10b8 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -138,3 +138,13 @@ os_socket_shutdown(bh_socket_t socket) shutdown(socket, SD_BOTH); return BHT_OK; } + +int +os_socket_inet_network(const char *cp, uint32 *out) +{ + if (!cp) + return BHT_ERROR; + + *out = inet_addr(cp); + return BHT_OK; +} \ No newline at end of file diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index 2392d7a667..60a852efef 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -16,8 +16,6 @@ static int app_argc; static char **app_argv; -#define MODULE_PATH ("--module-path=") - /* clang-format off */ static int print_help() @@ -41,6 +39,8 @@ print_help() printf(" --dir= Grant wasi access to the given host directories\n"); printf(" to the program, for example:\n"); printf(" --dir= --dir=\n"); + printf(" --addr-pool= Indicate network addresses in CIRD noation, \n"); + printf(" separate with ','\n"); #endif #if WASM_ENABLE_MULTI_MODULE != 0 printf(" --module-path= Indicate a module search path. default is current\n" @@ -244,6 +244,8 @@ main(int argc, char *argv[]) uint32 dir_list_size = 0; const char *env_list[8] = { NULL }; uint32 env_list_size = 0; + const char *addr_pool[8] = { NULL }; + uint32 addr_pool_size = 0; #endif #if WASM_ENABLE_DEBUG_INTERP != 0 char *ip_addr = NULL; @@ -312,9 +314,30 @@ main(int argc, char *argv[]) return print_help(); } } + /* TODO: parse the configuration file via --addr-pool-file */ + else if (!strncmp(argv[0], "--addr-pool=", strlen("--addr-pool="))) { + /* like: --addr-pool=100.200.244.255/30 */ + char *token = NULL; + + if ('\0' == argv[0][12]) + return print_help(); + + token = strtok(argv[0] + strlen("--addr-pool="), ","); + while (token) { + if (addr_pool_size >= sizeof(addr_pool) / sizeof(char *)) { + printf("Only allow max address number %d\n", + (int)(sizeof(addr_pool) / sizeof(char *))); + return -1; + } + + addr_pool[addr_pool_size++] = token; + token = strtok(NULL, ";"); + } + } #endif /* WASM_ENABLE_LIBC_WASI */ #if WASM_ENABLE_MULTI_MODULE != 0 - else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) { + else if (!strncmp(argv[0], + "--module-path=", strlen("--module-path="))) { module_search_path = handle_module_path(argv[0]); if (!strlen(module_search_path)) { return print_help(); @@ -422,6 +445,8 @@ main(int argc, char *argv[]) #if WASM_ENABLE_LIBC_WASI != 0 wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0, env_list, env_list_size, argv, argc); + + wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, addr_pool_size); #endif /* instantiate the module */ diff --git a/samples/network/CMakeLists.txt b/samples/network/CMakeLists.txt new file mode 100644 index 0000000000..80e63c899b --- /dev/null +++ b/samples/network/CMakeLists.txt @@ -0,0 +1,92 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.8...3.18) +project(network_sample) + +message(CHECK_START "Detecting WASI-SDK") +if(NOT (DEFINED WASI_SDK_DIR OR DEFINED CACHE{WASI_SDK_DIR})) + find_path(WASI_SDK_PARENT + wasi-sdk + PATHS /opt + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + if(WASI_SDK_PARENT) + set(WASI_SDK_DIR ${WASI_SDK_PARENT}/wasi-sdk) + endif() +endif() +if(WASI_SDK_DIR) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() + +if(NOT EXISTS ${WASI_SDK_DIR}) + message(FATAL_ERROR "Please set the absolute path of wasi-sdk with \'cmake -DWASI_SDK_HOME=XXX\'") +endif() + +message(CHECK_START "Detecting WASI_TOOLCHAIN_FILE at ${WASI_SDK_DIR}") +find_file(WASI_TOOLCHAIN_FILE + wasi-sdk.cmake + PATHS "${WASI_SDK_DIR}/share/cmake" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH +) +if(WASI_TOOLCHAIN_FILE) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() + +if(WASI_TOOLCHAIN_FILE-NOTFOUND) + message(FATAL_ERROR "Can not find wasi-sdk.cmake under ${WASI_SDK_DIR}") +endif() + +message(CHECK_START "Detecting WASI_SYS_ROOT at ${WASI_SDK_DIR}") +find_path(WASI_SYS_ROOT + wasi-sysroot + PATHS "${WASI_SDK_DIR}/share" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH +) +if(WASI_SYS_ROOT) + message(CHECK_PASS "found") + set(WASI_SYS_ROOT ${WASI_SYS_ROOT}/wasi-sysroot) +else() + message(CHECK_FAIL "not found") +endif() + +if(WASI_SYS_ROOT-NOTFOUND) + message(FATAL_ERROR "Can not find wasi-sysroot/ under ${WASI_SDK_DIR}") +endif() + +message(STATUS "WASI_SDK_DIR is ${WASI_SDK_DIR}") +message(STATUS "WASI_TOOLCHAIN_FILE is ${WASI_TOOLCHAIN_FILE}") +message(STATUS "WASI_SYS_ROOT is ${WASI_SYS_ROOT}") + +####################################### +include(ExternalProject) + +ExternalProject_Add(wasm-app + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src + UPDATE_COMMAND "" + PATCH_COMMAND "" + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -DWASI_SDK_PREFIX=${WASI_SDK_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE} + -DCMAKE_SYSROOT=${WASI_SYS_ROOT} + ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src + BUILD_COMMAND ${CMAKE_COMMAND} --build . + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy + tcp_client.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build + tcp_server.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build + tcp_client.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build + tcp_server.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build + && ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_CURRENT_SOURCE_DIR}/../../product-mini/platforms/linux/build/iwasm + ${CMAKE_CURRENT_SOURCE_DIR}/build/iwasm +) + +add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c) +add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c) diff --git a/samples/network/wasm-src/CMakeLists.txt b/samples/network/wasm-src/CMakeLists.txt new file mode 100644 index 0000000000..c21df60e5f --- /dev/null +++ b/samples/network/wasm-src/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 2.8...3.18) +project(network_sample_wasm_app) + +message(CHECK_START "Detecting WABT") +if(NOT (DEFINED WABT_DIR OR DEFINED CACHE{WABT_DIR})) + find_path(WABT_DIR + wabt + PATHS /opt + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + if(DEFINED WABT_DIR) + set(WABT_DIR ${WABT_DIR}/wabt) + endif() +endif() +if(WABT_DIR) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() + +message(CHECK_START "Detecting WASM_OBJDUMP at ${WABT_DIR}") +find_program(WASM_OBJDUMP + wasm-objdump + PATHS "${WABT_DIR}/bin" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH +) +if(WASM_OBJDUMP) + message(CHECK_PASS "found") +else() + message(CHECK_FAIL "not found") +endif() + +set(SRC ${CMAKE_CURRENT_SOURCE_DIR}) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake) + +function(COMPILE_WITH_CLANG SOURCE_FILE) + get_filename_component(FILE_NAME ${SOURCE_FILE} NAME_WLE) + + set(WASM_MODULE ${FILE_NAME}.wasm) + + set(MAIN_TARGET_NAME MODULE_${FILE_NAME}) + + add_executable(${MAIN_TARGET_NAME} ${SOURCE_FILE}) + set_target_properties(${MAIN_TARGET_NAME} PROPERTIES OUTPUT_NAME ${WASM_MODULE}) + target_link_libraries(${MAIN_TARGET_NAME} socket_wasi_ext) + + if(EXISTS ${WASM_OBJDUMP}) + message(STATUS "Dumping ${WASM_MODULE}...") + set(WASM_DUMP ${WASM_MODULE}.dump) + set(DUMP_TARGET_NAME DUMP_${FILE_NAME}) + + add_custom_command(OUTPUT ${WASM_DUMP} + COMMAND ${WASM_OBJDUMP} -dx ${WASM_MODULE} > ${WASM_DUMP} + COMMENT "Dumping ${WASM_MODULE}..." + DEPENDS ${MAIN_TARGET_NAME} + ) + + add_custom_target(${DUMP_TARGET_NAME} ALL + DEPENDS ${WASM_DUMP} + ) + endif() +endfunction() + +compile_with_clang(tcp_server.c) +compile_with_clang(tcp_client.c) diff --git a/samples/network/wasm-src/tcp_client.c b/samples/network/wasm-src/tcp_client.c new file mode 100644 index 0000000000..8f8a79ebb1 --- /dev/null +++ b/samples/network/wasm-src/tcp_client.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#endif + +int +main(int argc, char *argv[]) +{ + int socket_fd; + char buffer[1024] = { 0 }; + struct sockaddr_in server_address = { 0 }; + + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == -1) { + perror("Create socket failed"); + return EXIT_FAILURE; + } + + /* 127.0.0.1:1234 */ + server_address.sin_family = AF_INET; + server_address.sin_port = htons(1234); + server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (connect(socket_fd, (struct sockaddr *)&server_address, + sizeof(server_address)) + == -1) { + perror("Connect failed"); + close(socket_fd); + return EXIT_FAILURE; + } + + if (recv(socket_fd, buffer, 1024, 0) == -1) { + perror("Recv failed"); + close(socket_fd); + return EXIT_FAILURE; + } + printf("[Client] Received \"%s\"\n", buffer); + + close(socket_fd); + printf("[Client] BYE \n"); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/samples/network/wasm-src/tcp_server.c b/samples/network/wasm-src/tcp_server.c new file mode 100644 index 0000000000..b6c685b642 --- /dev/null +++ b/samples/network/wasm-src/tcp_server.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#endif + +int +main(int argc, char *argv[]) +{ + int socket_fd = -1, new_socket, addrlen = 0; + struct sockaddr_in addr = { 0 }; + const char *message = "Say Hi from the Server"; + uint32_t connections = 0; + + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd < 0) { + perror("Create socket failed"); + goto fail; + } + + /* 0.0.0.0:1234 */ + addr.sin_family = AF_INET; + addr.sin_port = htons(1234); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + addrlen = sizeof(addr); + if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) { + perror("Bind failed"); + goto fail; + } + + if (listen(socket_fd, 3) < 0) { + perror("Listen failed"); + goto fail; + } + + while (true) { + new_socket = + accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen); + if (new_socket < 0) { + perror("Accept failed"); + break; + } + + connections++; + +#ifndef __wasi__ + { + struct sockaddr client_addr = { 0 }; + if (getpeername(new_socket, &client_addr, &addrlen) != 0) { + perror("Getpeername failed"); + } + else { + printf("The connected address is %s\n", + inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr)); + } + } +#endif + + if (send(new_socket, message, strlen(message), 0) < 0) { + perror("Send failed"); + } + printf("[Server] Shuting down the new connection ... \n"); + shutdown(new_socket, SHUT_RDWR); + + if (connections == 1) { + break; + } + } + + printf("[Server] Shuting down ... \n"); + shutdown(socket_fd, SHUT_RDWR); + sleep(3); + printf("[Server] BYE \n"); + return EXIT_SUCCESS; + +fail: + printf("[Server] Shuting down ... \n"); + if (socket_fd >= 0) + close(socket_fd); + sleep(3); + return EXIT_FAILURE; +} \ No newline at end of file diff --git a/test-tools/build-wasi-sdk/include/.gitkeep b/test-tools/build-wasi-sdk/include/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 From d0a5ce739cfee3d6d5553e9c7d21fe91d9845b6f Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 10 Mar 2022 00:37:16 +0800 Subject: [PATCH 4/5] Add socket api document and update the sample --- README.md | 1 + doc/socket_api.md | 64 +++++++++ .../{network => socket-api}/CMakeLists.txt | 3 +- .../wasm-src/CMakeLists.txt | 10 +- samples/socket-api/wasm-src/inc/pthread.h | 124 ++++++++++++++++++ .../wasm-src/tcp_client.c | 0 .../wasm-src/tcp_server.c | 69 ++++++---- 7 files changed, 241 insertions(+), 30 deletions(-) create mode 100644 doc/socket_api.md rename samples/{network => socket-api}/CMakeLists.txt (97%) rename samples/{network => socket-api}/wasm-src/CMakeLists.txt (82%) create mode 100644 samples/socket-api/wasm-src/inc/pthread.h rename samples/{network => socket-api}/wasm-src/tcp_client.c (100%) rename samples/{network => socket-api}/wasm-src/tcp_server.c (56%) diff --git a/README.md b/README.md index 1465271bb0..3446d13b12 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ iwasm VM core - [Source debugging support](./doc/source_debugging.md), ref to [document](./doc/source_debugging.md) - [WAMR-IDE (Experimental)](./test-tools/wamr-ide) to develop WebAssembly applications with build, run and debug support, ref to [document](./test-tools/wamr-ide) - [XIP (Execution In Place) support](./doc/xip.md), ref to [document](./doc/xip.md) +- [Berkeley/Posix Socket support](./doc/socket_api.md), ref to [document](./doc/socket_api.md) and [sample](./samples/socket-api) ### WASM post-MVP features - [wasm-c-api](https://github.com/WebAssembly/wasm-c-api), ref to [document](doc/wasm_c_api.md) and [sample](samples/wasm-c-api) diff --git a/doc/socket_api.md b/doc/socket_api.md new file mode 100644 index 0000000000..5eeccce31d --- /dev/null +++ b/doc/socket_api.md @@ -0,0 +1,64 @@ +# How to use Berkeley/Posix Socket APIs in WebAssembly + +**_Berkeley sockets_** usually means an API for Internet sockets and Unix domain +sockets. A socket is an abstract representation of the local endpoint of a +network communication path. + +Currently, WAMR supports a limit set of all well-known functions: +`accept()`, `bind()`, `connect()`, `listen()`, `recv()`, `send()`, `shutdown()` +and `socket()`. Users can call those functions in WebAssembly code directly. +Those WebAssembly socket calls will be dispatched to the imported +functions and eventually will be implemented by host socket APIs. + +This document introduces a way to support _Berkeley/Posix Socket APIs_ in +WebAssembly code. + +## Patch the native code + +The first step is to include a header file of the WAMR socket extension in the +native source code. + +```c +#ifdef __wasi__ +#include +#endif +``` + +`__wasi__` is a Marco defined by WASI. The host compiler will not enable it. + +## CMake files + +It is recommended that the project should use CMake as its build system. Use +[_wasi-sdk_](https://github.com/WebAssembly/wasi-sdk) +as a toolchain to compile C/C++ to WebAssembly + +```bash +$ cmake -DWASI_SDK_PREFIX=${WASI_SDK_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE} + -DCMAKE_SYSROOT=${WASI_SYS_ROOT} + .. +``` + +In the *CMakeLists.txt*, include an extension of socket support and link with it. + +```cmake +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake) +add_executable(socket_example tcp_server.c) +target_link_libraries(socket_example socket_wasi_ext) +``` + +Now, the native code with socket APIs is ready for compilation. + +## Run with iwasm + +If having the _.wasm_, the last step is to run it with _iwasm_. + +The _iwasm_ should be compiled with `WAMR_BUILD_LIBC_WASI=1`. By default, it is +enabled. + +_iwasm_ accepts address ranges via an option, `--addr-pool`, to implement +the capability control. All IP address the WebAssebmly application may need to `bind()` or `connect()` should be announced first. Every IP address should be in CIRD notation. + +```bash +$ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm +``` diff --git a/samples/network/CMakeLists.txt b/samples/socket-api/CMakeLists.txt similarity index 97% rename from samples/network/CMakeLists.txt rename to samples/socket-api/CMakeLists.txt index 80e63c899b..ea397bf2c6 100644 --- a/samples/network/CMakeLists.txt +++ b/samples/socket-api/CMakeLists.txt @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception cmake_minimum_required(VERSION 2.8...3.18) -project(network_sample) +project(socket_api_sample) message(CHECK_START "Detecting WASI-SDK") if(NOT (DEFINED WASI_SDK_DIR OR DEFINED CACHE{WASI_SDK_DIR})) @@ -89,4 +89,5 @@ ExternalProject_Add(wasm-app ) add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c) +target_link_libraries(tcp_server pthread) add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c) diff --git a/samples/network/wasm-src/CMakeLists.txt b/samples/socket-api/wasm-src/CMakeLists.txt similarity index 82% rename from samples/network/wasm-src/CMakeLists.txt rename to samples/socket-api/wasm-src/CMakeLists.txt index c21df60e5f..f6c0366a4b 100644 --- a/samples/network/wasm-src/CMakeLists.txt +++ b/samples/socket-api/wasm-src/CMakeLists.txt @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception cmake_minimum_required(VERSION 2.8...3.18) -project(network_sample_wasm_app) +project(socket_api_sample_wasm_app) message(CHECK_START "Detecting WABT") if(NOT (DEFINED WABT_DIR OR DEFINED CACHE{WABT_DIR})) @@ -48,7 +48,15 @@ function(COMPILE_WITH_CLANG SOURCE_FILE) add_executable(${MAIN_TARGET_NAME} ${SOURCE_FILE}) set_target_properties(${MAIN_TARGET_NAME} PROPERTIES OUTPUT_NAME ${WASM_MODULE}) + target_include_directories(${MAIN_TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/inc) + target_compile_options(${MAIN_TARGET_NAME} INTERFACE -pthread) target_link_libraries(${MAIN_TARGET_NAME} socket_wasi_ext) + target_link_options(${MAIN_TARGET_NAME} PRIVATE + LINKER:--export=__heap_base + LINKER:--export=__data_end + LINKER:--shared-memory,--max-memory=196608 + LINKER:--no-check-features + ) if(EXISTS ${WASM_OBJDUMP}) message(STATUS "Dumping ${WASM_MODULE}...") diff --git a/samples/socket-api/wasm-src/inc/pthread.h b/samples/socket-api/wasm-src/inc/pthread.h new file mode 100644 index 0000000000..f9a8156c5b --- /dev/null +++ b/samples/socket-api/wasm-src/inc/pthread.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WAMR_LIB_PTHREAD_H +#define _WAMR_LIB_PTHREAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Data type define of pthread, mutex, cond and key */ +typedef unsigned int pthread_t; +typedef unsigned int pthread_mutex_t; +typedef unsigned int pthread_cond_t; +typedef unsigned int pthread_key_t; + +/* Thread APIs */ +int +pthread_create(pthread_t *thread, const void *attr, + void *(*start_routine)(void *), void *arg) + __attribute__((__import_module__("wamr_ext"), + __import_name__("pthread_create"))); + +int +pthread_join(pthread_t thread, void **retval) + __attribute__((__import_module__("wamr_ext_a"), + __import_name__("pthread_join"))); + +int +pthread_detach(pthread_t thread) + __attribute__((__import_module__("env"), + __import_name__("pthread_detach"))); + +int +pthread_cancel(pthread_t thread) + __attribute__((__import_module__("env"), + __import_name__("pthread_cancel"))); + +pthread_t +pthread_self(void) + __attribute__((__import_module__("env"), __import_name__("pthread_self"))); + +void +pthread_exit(void *retval) + __attribute__((__import_module__("env"), __import_name__("pthread_exit"))); + +/* Mutex APIs */ +int +pthread_mutex_init(pthread_mutex_t *mutex, const void *attr) + __attribute__((__import_module__("env"), + __import_name__("pthread_mutex_init"))); + +int +pthread_mutex_lock(pthread_mutex_t *mutex) + __attribute__((__import_module__("env"), + __import_name__("pthread_mutex_lock"))); + +int +pthread_mutex_unlock(pthread_mutex_t *mutex) + __attribute__((__import_module__("env"), + __import_name__("pthread_mutex_unlock"))); + +int +pthread_mutex_destroy(pthread_mutex_t *mutex) + __attribute__((__import_module__("env"), + __import_name__("pthread_mutex_destroy"))); + +/* Cond APIs */ +int +pthread_cond_init(pthread_cond_t *cond, const void *attr) + __attribute__((__import_module__("env"), + __import_name__("pthread_cond_init"))); + +int +pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) + __attribute__((__import_module__("env"), + __import_name__("pthread_cond_wait"))); + +int +pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + uint64_t useconds) + __attribute__((__import_module__("env"), + __import_name__("pthread_cond_timedwait"))); + +int +pthread_cond_signal(pthread_cond_t *cond) + __attribute__((__import_module__("env"), + __import_name__("pthread_cond_signal"))); + +int +pthread_cond_destroy(pthread_cond_t *cond) + __attribute__((__import_module__("env"), + __import_name__("pthread_cond_destroy"))); + +/* Pthread key APIs */ +int +pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) + __attribute__((__import_module__("env"), + __import_name__("pthread_key_create"))); + +int +pthread_setspecific(pthread_key_t key, const void *value) + __attribute__((__import_module__("env"), + __import_name__("pthread_setspecific"))); + +void * +pthread_getspecific(pthread_key_t key) + __attribute__((__import_module__("env"), + __import_name__("pthread_getspecific"))); + +int +pthread_key_delete(pthread_key_t key) + __attribute__((__import_module__("env"), + __import_name__("pthread_key_delete"))); + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WAMR_LIB_PTHREAD_H */ diff --git a/samples/network/wasm-src/tcp_client.c b/samples/socket-api/wasm-src/tcp_client.c similarity index 100% rename from samples/network/wasm-src/tcp_client.c rename to samples/socket-api/wasm-src/tcp_client.c diff --git a/samples/network/wasm-src/tcp_server.c b/samples/socket-api/wasm-src/tcp_server.c similarity index 56% rename from samples/network/wasm-src/tcp_server.c rename to samples/socket-api/wasm-src/tcp_server.c index b6c685b642..fae613abd1 100644 --- a/samples/network/wasm-src/tcp_server.c +++ b/samples/socket-api/wasm-src/tcp_server.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include #include @@ -14,13 +15,33 @@ #include #endif +#define WORKER_NUM 5 + +void * +run(void *arg) +{ + const char *message = "Say Hi from the Server"; + int new_socket = *(int *)arg; + + printf("[Server] Communicate with the new connection #%u @ 0x%lx... \n", + new_socket, pthread_self()); + + if (send(new_socket, message, strlen(message), 0) < 0) { + perror("Send failed"); + } + + printf("[Server] Shuting down the new connection #%u... \n", new_socket); + shutdown(new_socket, SHUT_RDWR); +} + int main(int argc, char *argv[]) { - int socket_fd = -1, new_socket, addrlen = 0; + int socket_fd = -1, addrlen = 0; struct sockaddr_in addr = { 0 }; - const char *message = "Say Hi from the Server"; - uint32_t connections = 0; + unsigned connections = 0; + pthread_t workers[WORKER_NUM] = { 0 }; + int client_sock_fds[WORKER_NUM] = { 0 }; socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { @@ -44,38 +65,30 @@ main(int argc, char *argv[]) goto fail; } - while (true) { - new_socket = + while (connections < WORKER_NUM) { + client_sock_fds[connections] = accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen); - if (new_socket < 0) { + if (client_sock_fds[connections] < 0) { perror("Accept failed"); break; } - connections++; - -#ifndef __wasi__ - { - struct sockaddr client_addr = { 0 }; - if (getpeername(new_socket, &client_addr, &addrlen) != 0) { - perror("Getpeername failed"); - } - else { - printf("The connected address is %s\n", - inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr)); - } + if (pthread_create(&workers[connections], NULL, run, + &client_sock_fds[connections])) { + perror("Create a worker thread failed"); + shutdown(client_sock_fds[connections], SHUT_RDWR); + break; } -#endif - if (send(new_socket, message, strlen(message), 0) < 0) { - perror("Send failed"); - } - printf("[Server] Shuting down the new connection ... \n"); - shutdown(new_socket, SHUT_RDWR); + connections++; + } - if (connections == 1) { - break; - } + if (connections == WORKER_NUM) { + printf("Achieve maximum amount of connections\n"); + } + + for (int i = 0; i < WORKER_NUM; i++) { + pthread_join(workers[i], NULL); } printf("[Server] Shuting down ... \n"); @@ -90,4 +103,4 @@ main(int argc, char *argv[]) close(socket_fd); sleep(3); return EXIT_FAILURE; -} \ No newline at end of file +} From d5f4f18dbe5cf9a6264bd817885f172cba2858bd Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 10 Mar 2022 14:03:09 +0800 Subject: [PATCH 5/5] Refine socket-api sample (#1040) Refine the source code of tcp_server.c and tcp_client.c Add building of iwasm with lib-pthread and libc-wasi enabled Add sample document Update iwasm --addr-pool argument description --- README.md | 1 + doc/socket_api.md | 2 + product-mini/platforms/posix/main.c | 6 +- samples/socket-api/CMakeLists.txt | 83 ++++++++++++-- samples/socket-api/README.md | 57 ++++++++++ samples/socket-api/wasm-src/CMakeLists.txt | 1 + samples/socket-api/wasm-src/inc/.gitkeep | 0 samples/socket-api/wasm-src/inc/pthread.h | 124 --------------------- samples/socket-api/wasm-src/tcp_client.c | 23 ++-- samples/socket-api/wasm-src/tcp_server.c | 30 +++-- 10 files changed, 178 insertions(+), 149 deletions(-) create mode 100644 samples/socket-api/README.md create mode 100644 samples/socket-api/wasm-src/inc/.gitkeep delete mode 100644 samples/socket-api/wasm-src/inc/pthread.h diff --git a/README.md b/README.md index 3446d13b12..4645bc4f7f 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a - **[multi-module](./samples/multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/). - **[ref-types](./samples/ref-types)**: Demonstrating how to call wasm functions with argument of externref type introduced by [reference types proposal](https://github.com/WebAssembly/reference-types). - **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's. +- **[socket-api](./samples/socket-api/README.md)**: Demonstrating how to run wasm tcp server and tcp client applications, and how they communicate with each other. - **[workload](./samples/workload/README.md)**: Demonstrating how to build and run some complex workloads, e.g. tensorflow-lite, XNNPACK, wasm-av1, meshoptimizer and bwa. diff --git a/doc/socket_api.md b/doc/socket_api.md index 5eeccce31d..91f668e55a 100644 --- a/doc/socket_api.md +++ b/doc/socket_api.md @@ -62,3 +62,5 @@ the capability control. All IP address the WebAssebmly application may need to ` ```bash $ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm ``` + +Refer to [socket api sample](../samples/socket-api) for more details. diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index 60a852efef..466bda89be 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -39,8 +39,10 @@ print_help() printf(" --dir= Grant wasi access to the given host directories\n"); printf(" to the program, for example:\n"); printf(" --dir= --dir=\n"); - printf(" --addr-pool= Indicate network addresses in CIRD noation, \n"); - printf(" separate with ','\n"); + printf(" --addr-pool= Grant wasi access to the given network addresses in\n"); + printf(" CIRD notation to the program, seperated with ',',\n"); + printf(" for example:\n"); + printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n"); #endif #if WASM_ENABLE_MULTI_MODULE != 0 printf(" --module-path= Indicate a module search path. default is current\n" diff --git a/samples/socket-api/CMakeLists.txt b/samples/socket-api/CMakeLists.txt index ea397bf2c6..16cafdb45e 100644 --- a/samples/socket-api/CMakeLists.txt +++ b/samples/socket-api/CMakeLists.txt @@ -4,7 +4,10 @@ cmake_minimum_required(VERSION 2.8...3.18) project(socket_api_sample) -message(CHECK_START "Detecting WASI-SDK") +####################################### +## Detect toolchain +####################################### +message(CHECK_START "Detecting WASI-SDK at /opt/wasi-sdk") if(NOT (DEFINED WASI_SDK_DIR OR DEFINED CACHE{WASI_SDK_DIR})) find_path(WASI_SDK_PARENT wasi-sdk @@ -23,7 +26,7 @@ else() endif() if(NOT EXISTS ${WASI_SDK_DIR}) - message(FATAL_ERROR "Please set the absolute path of wasi-sdk with \'cmake -DWASI_SDK_HOME=XXX\'") + message(FATAL_ERROR "Please install WASI-SDK under /opt/wasi-sdk") endif() message(CHECK_START "Detecting WASI_TOOLCHAIN_FILE at ${WASI_SDK_DIR}") @@ -65,14 +68,19 @@ message(STATUS "WASI_SDK_DIR is ${WASI_SDK_DIR}") message(STATUS "WASI_TOOLCHAIN_FILE is ${WASI_TOOLCHAIN_FILE}") message(STATUS "WASI_SYS_ROOT is ${WASI_SYS_ROOT}") -####################################### +############################################################### +## Build socket applications of wasm version and native version +############################################################### include(ExternalProject) ExternalProject_Add(wasm-app SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src UPDATE_COMMAND "" PATCH_COMMAND "" - CONFIGURE_COMMAND ${CMAKE_COMMAND} + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/../../wamr-sdk/app/libc-builtin-sysroot/include/pthread.h + ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/inc + && ${CMAKE_COMMAND} -DWASI_SDK_PREFIX=${WASI_SDK_DIR} -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE} -DCMAKE_SYSROOT=${WASI_SYS_ROOT} @@ -83,11 +91,72 @@ ExternalProject_Add(wasm-app tcp_server.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build tcp_client.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build tcp_server.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build - && ${CMAKE_COMMAND} -E create_symlink - ${CMAKE_CURRENT_SOURCE_DIR}/../../product-mini/platforms/linux/build/iwasm - ${CMAKE_CURRENT_SOURCE_DIR}/build/iwasm ) add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c) target_link_libraries(tcp_server pthread) add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c) + +############################################ +## Build iwasm with wasi and pthread support +############################################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Reset linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# Set WAMR features + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + else () + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Release) +endif () + +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_AOT 1) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_LIB_PTHREAD 1) + +# compiling and linking flags +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + +# build vmlib static lib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +# build iwasm +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) +set (RUNTIME_SOURCE_ALL + ${CMAKE_CURRENT_LIST_DIR}/../../product-mini/platforms/linux/main.c + ${UNCOMMON_SHARED_SOURCE} +) +add_executable (iwasm ${RUNTIME_SOURCE_ALL}) +target_link_libraries(iwasm vmlib -lpthread -lm) diff --git a/samples/socket-api/README.md b/samples/socket-api/README.md new file mode 100644 index 0000000000..320f4a6ada --- /dev/null +++ b/samples/socket-api/README.md @@ -0,0 +1,57 @@ +"socket-api" sample introduction +================================ + +This sample demonstrates how to use WAMR socket-api to develop wasm network applications. +Two wasm applications are provided: tcp-server and tcp-client, and this sample demonstrates +how they communicate with each other. + +## Preparation + +Please install WASI SDK, download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. +And install wabt, download the [wabt release](https://github.com/WebAssembly/wabt/releases) and extract the archive to default path `/opt/wabt` + +## Build the sample + +```bash +mkdir build +cd build +cmake .. +make +``` + +The file `tcp_server.wasm`, `tcp_client.wasm` and `iwasm` will be created. +And also file `tcp_server` and `tcp_client` of native version are created. + +Note that iwasm is built with libc-wasi and lib-pthread enabled. + +## Run workload + +Start the tcp server, which opens port 1234 and waits for clients to connect. +```bash +cd build +./iwasm --addr-pool=0.0.0.0/15 tcp_server.wasm +``` + +Start the tcp client, which connects the server and receives message. +```bash +cd build +./iwasm --addr-pool=127.0.0.1/15 tcp_client.wasm +``` + +The output of client is like: +```bash +[Client] Create socket +[Client] Connect socket +[Client] Client receive +[Client] 115 bytes received: +Buffer recieved: +Say Hi from the Server +Say Hi from the Server +Say Hi from the Server +Say Hi from the Server +Say Hi from the Server + +[Client] BYE +``` + +Refer to [socket api document](../../doc/socket_api.md) for more details. diff --git a/samples/socket-api/wasm-src/CMakeLists.txt b/samples/socket-api/wasm-src/CMakeLists.txt index f6c0366a4b..b83c8f88fd 100644 --- a/samples/socket-api/wasm-src/CMakeLists.txt +++ b/samples/socket-api/wasm-src/CMakeLists.txt @@ -56,6 +56,7 @@ function(COMPILE_WITH_CLANG SOURCE_FILE) LINKER:--export=__data_end LINKER:--shared-memory,--max-memory=196608 LINKER:--no-check-features + LINKER:--allow-undefined ) if(EXISTS ${WASM_OBJDUMP}) diff --git a/samples/socket-api/wasm-src/inc/.gitkeep b/samples/socket-api/wasm-src/inc/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/socket-api/wasm-src/inc/pthread.h b/samples/socket-api/wasm-src/inc/pthread.h deleted file mode 100644 index f9a8156c5b..0000000000 --- a/samples/socket-api/wasm-src/inc/pthread.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef _WAMR_LIB_PTHREAD_H -#define _WAMR_LIB_PTHREAD_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* Data type define of pthread, mutex, cond and key */ -typedef unsigned int pthread_t; -typedef unsigned int pthread_mutex_t; -typedef unsigned int pthread_cond_t; -typedef unsigned int pthread_key_t; - -/* Thread APIs */ -int -pthread_create(pthread_t *thread, const void *attr, - void *(*start_routine)(void *), void *arg) - __attribute__((__import_module__("wamr_ext"), - __import_name__("pthread_create"))); - -int -pthread_join(pthread_t thread, void **retval) - __attribute__((__import_module__("wamr_ext_a"), - __import_name__("pthread_join"))); - -int -pthread_detach(pthread_t thread) - __attribute__((__import_module__("env"), - __import_name__("pthread_detach"))); - -int -pthread_cancel(pthread_t thread) - __attribute__((__import_module__("env"), - __import_name__("pthread_cancel"))); - -pthread_t -pthread_self(void) - __attribute__((__import_module__("env"), __import_name__("pthread_self"))); - -void -pthread_exit(void *retval) - __attribute__((__import_module__("env"), __import_name__("pthread_exit"))); - -/* Mutex APIs */ -int -pthread_mutex_init(pthread_mutex_t *mutex, const void *attr) - __attribute__((__import_module__("env"), - __import_name__("pthread_mutex_init"))); - -int -pthread_mutex_lock(pthread_mutex_t *mutex) - __attribute__((__import_module__("env"), - __import_name__("pthread_mutex_lock"))); - -int -pthread_mutex_unlock(pthread_mutex_t *mutex) - __attribute__((__import_module__("env"), - __import_name__("pthread_mutex_unlock"))); - -int -pthread_mutex_destroy(pthread_mutex_t *mutex) - __attribute__((__import_module__("env"), - __import_name__("pthread_mutex_destroy"))); - -/* Cond APIs */ -int -pthread_cond_init(pthread_cond_t *cond, const void *attr) - __attribute__((__import_module__("env"), - __import_name__("pthread_cond_init"))); - -int -pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) - __attribute__((__import_module__("env"), - __import_name__("pthread_cond_wait"))); - -int -pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - uint64_t useconds) - __attribute__((__import_module__("env"), - __import_name__("pthread_cond_timedwait"))); - -int -pthread_cond_signal(pthread_cond_t *cond) - __attribute__((__import_module__("env"), - __import_name__("pthread_cond_signal"))); - -int -pthread_cond_destroy(pthread_cond_t *cond) - __attribute__((__import_module__("env"), - __import_name__("pthread_cond_destroy"))); - -/* Pthread key APIs */ -int -pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) - __attribute__((__import_module__("env"), - __import_name__("pthread_key_create"))); - -int -pthread_setspecific(pthread_key_t key, const void *value) - __attribute__((__import_module__("env"), - __import_name__("pthread_setspecific"))); - -void * -pthread_getspecific(pthread_key_t key) - __attribute__((__import_module__("env"), - __import_name__("pthread_getspecific"))); - -int -pthread_key_delete(pthread_key_t key) - __attribute__((__import_module__("env"), - __import_name__("pthread_key_delete"))); - -#ifdef __cplusplus -} -#endif - -#endif /* end of _WAMR_LIB_PTHREAD_H */ diff --git a/samples/socket-api/wasm-src/tcp_client.c b/samples/socket-api/wasm-src/tcp_client.c index 8f8a79ebb1..4fcf87074d 100644 --- a/samples/socket-api/wasm-src/tcp_client.c +++ b/samples/socket-api/wasm-src/tcp_client.c @@ -17,10 +17,11 @@ int main(int argc, char *argv[]) { - int socket_fd; + int socket_fd, ret, total_size = 0; char buffer[1024] = { 0 }; struct sockaddr_in server_address = { 0 }; + printf("[Client] Create socket\n"); socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd == -1) { perror("Create socket failed"); @@ -32,6 +33,7 @@ main(int argc, char *argv[]) server_address.sin_port = htons(1234); server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + printf("[Client] Connect socket\n"); if (connect(socket_fd, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) { @@ -40,14 +42,21 @@ main(int argc, char *argv[]) return EXIT_FAILURE; } - if (recv(socket_fd, buffer, 1024, 0) == -1) { - perror("Recv failed"); - close(socket_fd); - return EXIT_FAILURE; + printf("[Client] Client receive\n"); + while (1) { + ret = recv(socket_fd, buffer + total_size, sizeof(buffer) - total_size, + 0); + if (ret <= 0) + break; + total_size += ret; + } + + printf("[Client] %d bytes received:\n", total_size); + if (total_size > 0) { + printf("Buffer recieved:\n%s\n", buffer); } - printf("[Client] Received \"%s\"\n", buffer); close(socket_fd); printf("[Client] BYE \n"); return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/samples/socket-api/wasm-src/tcp_server.c b/samples/socket-api/wasm-src/tcp_server.c index fae613abd1..4b8b4362a9 100644 --- a/samples/socket-api/wasm-src/tcp_server.c +++ b/samples/socket-api/wasm-src/tcp_server.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -20,18 +21,24 @@ void * run(void *arg) { - const char *message = "Say Hi from the Server"; + const char *message = "Say Hi from the Server\n"; int new_socket = *(int *)arg; + int i; - printf("[Server] Communicate with the new connection #%u @ 0x%lx... \n", - new_socket, pthread_self()); + printf("[Server] Communicate with the new connection #%u @ %p ..\n", + new_socket, (void *)(uintptr_t)pthread_self()); - if (send(new_socket, message, strlen(message), 0) < 0) { - perror("Send failed"); + for (i = 0; i < 5; i++) { + if (send(new_socket, message, strlen(message), 0) < 0) { + perror("Send failed"); + break; + } } - printf("[Server] Shuting down the new connection #%u... \n", new_socket); + printf("[Server] Shuting down the new connection #%u ..\n", new_socket); shutdown(new_socket, SHUT_RDWR); + + return NULL; } int @@ -43,6 +50,7 @@ main(int argc, char *argv[]) pthread_t workers[WORKER_NUM] = { 0 }; int client_sock_fds[WORKER_NUM] = { 0 }; + printf("[Server] Create socket\n"); socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { perror("Create socket failed"); @@ -54,17 +62,20 @@ main(int argc, char *argv[]) addr.sin_port = htons(1234); addr.sin_addr.s_addr = htonl(INADDR_ANY); + printf("[Server] Bind socket\n"); addrlen = sizeof(addr); if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) { perror("Bind failed"); goto fail; } + printf("[Server] Listening on socket\n"); if (listen(socket_fd, 3) < 0) { perror("Listen failed"); goto fail; } + printf("[Server] Wait for clients to connect ..\n"); while (connections < WORKER_NUM) { client_sock_fds[connections] = accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen); @@ -73,6 +84,7 @@ main(int argc, char *argv[]) break; } + printf("[Server] Client connected\n"); if (pthread_create(&workers[connections], NULL, run, &client_sock_fds[connections])) { perror("Create a worker thread failed"); @@ -84,21 +96,21 @@ main(int argc, char *argv[]) } if (connections == WORKER_NUM) { - printf("Achieve maximum amount of connections\n"); + printf("[Server] Achieve maximum amount of connections\n"); } for (int i = 0; i < WORKER_NUM; i++) { pthread_join(workers[i], NULL); } - printf("[Server] Shuting down ... \n"); + printf("[Server] Shuting down ..\n"); shutdown(socket_fd, SHUT_RDWR); sleep(3); printf("[Server] BYE \n"); return EXIT_SUCCESS; fail: - printf("[Server] Shuting down ... \n"); + printf("[Server] Shuting down ..\n"); if (socket_fd >= 0) close(socket_fd); sleep(3);