From ab929c20a3602f1c7e69f1d9d73db63c661b58b2 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Wed, 14 Sep 2022 19:49:18 +0800 Subject: [PATCH 01/29] Add check for code section size, fix interp float operations (#1480) And enable classic interpreter instead fast interpreter when llvm jit is enabled, so as to fix the issue that llvm jit cannot handle opcode drop_64/select_64. --- build-scripts/runtime_lib.cmake | 2 +- core/iwasm/interpreter/wasm_interp_classic.c | 40 +++++++-- core/iwasm/interpreter/wasm_interp_fast.c | 41 +++++++-- core/iwasm/interpreter/wasm_loader.c | 11 ++- core/iwasm/interpreter/wasm_mini_loader.c | 8 +- .../shared/platform/alios/platform_internal.h | 2 + core/shared/platform/common/math/math.c | 89 +++++++++++++++++++ core/shared/platform/riot/platform_internal.h | 2 + .../platform/zephyr/platform_internal.h | 2 + 9 files changed, 175 insertions(+), 22 deletions(-) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 967aa344..a7e968bf 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -52,7 +52,7 @@ endif () ################ optional according to settings ################ if (WAMR_BUILD_INTERP EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1 OR WAMR_BUILD_FAST_JIT EQUAL 1) - if (WAMR_BUILD_FAST_JIT EQUAL 1) + if (WAMR_BUILD_FAST_JIT EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1) set (WAMR_BUILD_FAST_INTERP 0) endif () include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 9df1df08..494b6825 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -198,6 +198,30 @@ popcount64(uint64 u) return ret; } +static float +local_copysignf(float x, float y) +{ + union { + float f; + uint32_t i; + } ux = { x }, uy = { y }; + ux.i &= 0x7fffffff; + ux.i |= uy.i & 0x80000000; + return ux.f; +} + +static double +local_copysign(double x, double y) +{ + union { + double f; + uint64_t i; + } ux = { x }, uy = { y }; + ux.i &= -1ULL / 2; + ux.i |= uy.i & 1ULL << 63; + return ux.f; +} + static uint64 read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) { @@ -2580,7 +2604,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* numberic instructions of f32 */ HANDLE_OP(WASM_OP_F32_ABS) { - DEF_OP_MATH(float32, F32, fabs); + DEF_OP_MATH(float32, F32, fabsf); HANDLE_OP_END(); } @@ -2597,31 +2621,31 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_F32_CEIL) { - DEF_OP_MATH(float32, F32, ceil); + DEF_OP_MATH(float32, F32, ceilf); HANDLE_OP_END(); } HANDLE_OP(WASM_OP_F32_FLOOR) { - DEF_OP_MATH(float32, F32, floor); + DEF_OP_MATH(float32, F32, floorf); HANDLE_OP_END(); } HANDLE_OP(WASM_OP_F32_TRUNC) { - DEF_OP_MATH(float32, F32, trunc); + DEF_OP_MATH(float32, F32, truncf); HANDLE_OP_END(); } HANDLE_OP(WASM_OP_F32_NEAREST) { - DEF_OP_MATH(float32, F32, rint); + DEF_OP_MATH(float32, F32, rintf); HANDLE_OP_END(); } HANDLE_OP(WASM_OP_F32_SQRT) { - DEF_OP_MATH(float32, F32, sqrt); + DEF_OP_MATH(float32, F32, sqrtf); HANDLE_OP_END(); } @@ -2687,7 +2711,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F32(); a = POP_F32(); - PUSH_F32(signbit(b) ? -fabs(a) : fabs(a)); + PUSH_F32(local_copysignf(a, b)); HANDLE_OP_END(); } @@ -2801,7 +2825,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F64(); a = POP_F64(); - PUSH_F64(signbit(b) ? -fabs(a) : fabs(a)); + PUSH_F64(local_copysign(a, b)); HANDLE_OP_END(); } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 6fad303e..e27919dd 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -189,6 +189,30 @@ popcount64(uint64 u) return ret; } +static float +local_copysignf(float x, float y) +{ + union { + float f; + uint32_t i; + } ux = { x }, uy = { y }; + ux.i &= 0x7fffffff; + ux.i |= uy.i & 0x80000000; + return ux.f; +} + +static double +local_copysign(double x, double y) +{ + union { + double f; + uint64_t i; + } ux = { x }, uy = { y }; + ux.i &= -1ULL / 2; + ux.i |= uy.i & 1ULL << 63; + return ux.f; +} + #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 #define LOAD_U32_WITH_2U16S(addr) (*(uint32 *)(addr)) #define LOAD_PTR(addr) (*(void **)(addr)) @@ -2415,7 +2439,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* numberic instructions of f32 */ HANDLE_OP(WASM_OP_F32_ABS) { - DEF_OP_MATH(float32, F32, fabs); + DEF_OP_MATH(float32, F32, fabsf); HANDLE_OP_END(); } @@ -2433,31 +2457,31 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_F32_CEIL) { - DEF_OP_MATH(float32, F32, ceil); + DEF_OP_MATH(float32, F32, ceilf); HANDLE_OP_END(); } HANDLE_OP(WASM_OP_F32_FLOOR) { - DEF_OP_MATH(float32, F32, floor); + DEF_OP_MATH(float32, F32, floorf); HANDLE_OP_END(); } HANDLE_OP(WASM_OP_F32_TRUNC) { - DEF_OP_MATH(float32, F32, trunc); + DEF_OP_MATH(float32, F32, truncf); HANDLE_OP_END(); } HANDLE_OP(WASM_OP_F32_NEAREST) { - DEF_OP_MATH(float32, F32, rint); + DEF_OP_MATH(float32, F32, rintf); HANDLE_OP_END(); } HANDLE_OP(WASM_OP_F32_SQRT) { - DEF_OP_MATH(float32, F32, sqrt); + DEF_OP_MATH(float32, F32, sqrtf); HANDLE_OP_END(); } @@ -2525,8 +2549,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = *(float32 *)(frame_lp + GET_OFFSET()); a = *(float32 *)(frame_lp + GET_OFFSET()); - *(float32 *)(frame_lp + GET_OFFSET()) = - (float32)(signbit(b) ? -fabs(a) : fabs(a)); + *(float32 *)(frame_lp + GET_OFFSET()) = local_copysignf(a, b); HANDLE_OP_END(); } @@ -2642,7 +2665,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F64(); a = POP_F64(); - PUSH_F64(signbit(b) ? -fabs(a) : fabs(a)); + PUSH_F64(local_copysign(a, b)); HANDLE_OP_END(); } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 0aeda3ec..e424ebca 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -3278,6 +3278,13 @@ load_from_sections(WASMModule *module, WASMSection *sections, error_buf_size)) { return false; } + + if (i == module->function_count - 1 + && func->code + func->code_size != buf_code_end) { + set_error_buf(error_buf, error_buf_size, + "code section size mismatch"); + return false; + } } if (!module->possible_memory_grow) { @@ -7344,7 +7351,7 @@ re_scan: else if (is_64bit_type(*(loader_ctx->frame_ref - 1))) { loader_ctx->frame_ref -= 2; loader_ctx->stack_cell_num -= 2; -#if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) +#if WASM_ENABLE_FAST_INTERP == 0 *(p - 1) = WASM_OP_DROP_64; #endif #if WASM_ENABLE_FAST_INTERP != 0 @@ -7406,7 +7413,7 @@ re_scan: break; case REF_I64_2: case REF_F64_2: -#if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) +#if WASM_ENABLE_FAST_INTERP == 0 *(p - 1) = WASM_OP_SELECT_64; #endif #if WASM_ENABLE_FAST_INTERP != 0 diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index ac240689..fab97dbd 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2115,6 +2115,10 @@ load_from_sections(WASMModule *module, WASMSection *sections, error_buf_size)) { return false; } + + if (i == module->function_count - 1) { + bh_assert(func->code + func->code_size == buf_code_end); + } } if (!module->possible_memory_grow) { @@ -5545,7 +5549,7 @@ re_scan: else if (is_64bit_type(*(loader_ctx->frame_ref - 1))) { loader_ctx->frame_ref -= 2; loader_ctx->stack_cell_num -= 2; -#if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) +#if WASM_ENABLE_FAST_INTERP == 0 *(p - 1) = WASM_OP_DROP_64; #endif #if WASM_ENABLE_FAST_INTERP != 0 @@ -5591,7 +5595,7 @@ re_scan: break; case REF_I64_2: case REF_F64_2: -#if (WASM_ENABLE_FAST_INTERP == 0) || (WASM_ENABLE_JIT != 0) +#if WASM_ENABLE_FAST_INTERP == 0 *(p - 1) = WASM_OP_SELECT_64; #endif #if WASM_ENABLE_FAST_INTERP != 0 diff --git a/core/shared/platform/alios/platform_internal.h b/core/shared/platform/alios/platform_internal.h index ac9fb5ca..f6a4ba11 100644 --- a/core/shared/platform/alios/platform_internal.h +++ b/core/shared/platform/alios/platform_internal.h @@ -52,11 +52,13 @@ double fmax(double x, double y); double rint(double x); double fabs(double x); double trunc(double x); +float sqrtf(float x); float floorf(float x); float ceilf(float x); float fminf(float x, float y); float fmaxf(float x, float y); float rintf(float x); +float fabsf(float x); float truncf(float x); int signbit(double x); int isnan(double x); diff --git a/core/shared/platform/common/math/math.c b/core/shared/platform/common/math/math.c index a1679f25..a9fcf021 100644 --- a/core/shared/platform/common/math/math.c +++ b/core/shared/platform/common/math/math.c @@ -622,6 +622,74 @@ freebsd_atan2(double y, double x) } } +static float +freebsd_sqrtf(float x) +{ + float z; + int32_t sign = (int)0x80000000; + int32_t ix, s, q, m, t, i; + u_int32_t r; + + GET_FLOAT_WORD(ix, x); + + /* take care of Inf and NaN */ + if ((ix & 0x7f800000) == 0x7f800000) { + return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if (ix <= 0) { + if ((ix & (~sign)) == 0) + return x; /* sqrt(+-0) = +-0 */ + else if (ix < 0) + return (x - x) / (x - x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix >> 23); + if (m == 0) { /* subnormal x */ + for (i = 0; (ix & 0x00800000) == 0; i++) + ix <<= 1; + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix & 0x007fffff) | 0x00800000; + if (m & 1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s + r; + if (t <= ix) { + s = t + r; + ix -= t; + q += r; + } + ix += ix; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if (ix != 0) { + z = one - tiny; /* trigger inexact flag */ + if (z >= one) { + z = one + tiny; + if (z > one) + q += 2; + else + q += (q & 1); + } + } + ix = (q >> 1) + 0x3f000000; + ix += (m << 23); + SET_FLOAT_WORD(z, ix); + return z; +} + static double freebsd_sqrt(double x) /* wrapper sqrt */ { @@ -935,6 +1003,15 @@ freebsd_isnan(double d) } } +static float +freebsd_fabsf(float x) +{ + u_int32_t ix; + GET_FLOAT_WORD(ix, x); + SET_FLOAT_WORD(x, ix & 0x7fffffff); + return x; +} + static double freebsd_fabs(double x) { @@ -1537,6 +1614,12 @@ signbit(double x) return ((__HI(x) & 0x80000000) >> 31); } +float +fabsf(float x) +{ + return freebsd_fabsf(x); +} + float truncf(float x) { @@ -1573,6 +1656,12 @@ fmaxf(float x, float y) return freebsd_fmaxf(x, y); } +float +sqrtf(float x) +{ + return freebsd_sqrtf(x); +} + double pow(double x, double y) { diff --git a/core/shared/platform/riot/platform_internal.h b/core/shared/platform/riot/platform_internal.h index 924ec78e..8fec6dd0 100644 --- a/core/shared/platform/riot/platform_internal.h +++ b/core/shared/platform/riot/platform_internal.h @@ -63,11 +63,13 @@ double fmax(double x, double y); double rint(double x); double fabs(double x); double trunc(double x); +float sqrtf(float x); float floorf(float x); float ceilf(float x); float fminf(float x, float y); float fmaxf(float x, float y); float rintf(float x); +float fabsf(float x); float truncf(float x); int signbit(double x); int isnan(double x); diff --git a/core/shared/platform/zephyr/platform_internal.h b/core/shared/platform/zephyr/platform_internal.h index ffc9c2d6..f4683d93 100644 --- a/core/shared/platform/zephyr/platform_internal.h +++ b/core/shared/platform/zephyr/platform_internal.h @@ -78,11 +78,13 @@ double fmax(double x, double y); double rint(double x); double fabs(double x); double trunc(double x); +float sqrtf(float x); float floorf(float x); float ceilf(float x); float fminf(float x, float y); float fmaxf(float x, float y); float rintf(float x); +float fabsf(float x); float truncf(float x); int signbit(double x); int isnan(double x); From bbea005db6f201c63decb4d1d9e430883aa73bd1 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Thu, 15 Sep 2022 15:09:01 +0800 Subject: [PATCH 02/29] Make libc-builtin buffered printf be a common feature (#1483) Add macros to control whether to use the libc-builtin buffered printf and the buffer size. --- .../libc-builtin/libc_builtin_wrapper.c | 21 ++++++++++++++++--- .../shared/platform/nuttx/platform_internal.h | 4 ++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 00c93b6d..c24f789a 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -345,9 +345,24 @@ sprintf_out(int c, struct str_context *ctx) return c; } -#ifdef BH_PLATFORM_OPENRTOS -PRIVILEGED_DATA static char print_buf[128] = { 0 }; -PRIVILEGED_DATA static int print_buf_size = 0; +#ifndef BUILTIN_LIBC_BUFFERED_PRINTF +#define BUILTIN_LIBC_BUFFERED_PRINTF 0 +#endif + +#ifndef BUILTIN_LIBC_BUFFERED_PRINT_SIZE +#define BUILTIN_LIBC_BUFFERED_PRINT_SIZE 128 +#endif +#ifndef BUILTIN_LIBC_BUFFERED_PRINT_PREFIX +#define BUILTIN_LIBC_BUFFERED_PRINT_PREFIX +#endif + +#if BUILTIN_LIBC_BUFFERED_PRINTF != 0 + +BUILTIN_LIBC_BUFFERED_PRINT_PREFIX +static char print_buf[BUILTIN_LIBC_BUFFERED_PRINT_SIZE] = { 0 }; + +BUILTIN_LIBC_BUFFERED_PRINT_PREFIX +static int print_buf_size = 0; static int printf_out(int c, struct str_context *ctx) diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h index 3979f9cc..637fa21f 100644 --- a/core/shared/platform/nuttx/platform_internal.h +++ b/core/shared/platform/nuttx/platform_internal.h @@ -77,6 +77,10 @@ typedef sem_t korp_sem; #define CONFIG_HAS_ISATTY 0 #endif +#define BUILTIN_LIBC_BUFFERED_PRINTF 1 +#define BUILTIN_LIBC_BUFFERED_PRINT_SIZE 128 +#define BUILTIN_LIBC_BUFFERED_PRINT_PREFIX + /* * NuttX doesn't have openat family. */ From edaff3c6ec2063595d15fc075577db659ca34e5f Mon Sep 17 00:00:00 2001 From: Shengyun Zhou Date: Thu, 15 Sep 2022 17:13:33 +0800 Subject: [PATCH 03/29] thread-mgr: Prevent an already detached thread from being detached again (#1487) If WASM app has called pthread_detach() to detach a thread, it will be detached again when thread exits. Attempting to detach an already detached thread may result in crash in musl-libc. This patch fixes it. --- core/iwasm/libraries/thread-mgr/thread_manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 93212b0c..2e15ac54 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -705,7 +705,7 @@ wasm_cluster_detach_thread(WASMExecEnv *exec_env) os_mutex_unlock(&cluster_list_lock); return 0; } - if (exec_env->wait_count == 0) { + if (exec_env->wait_count == 0 && !exec_env->thread_is_detached) { /* Only detach current thread when there is no other thread joining it, otherwise let the system resources for the thread be released after joining */ From 1eedde7c33819027285f0624640e682c70213edd Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 16 Sep 2022 13:06:46 +0900 Subject: [PATCH 04/29] Fix several issues related to AOT debug (#1492) --- core/iwasm/aot/debug/elf_parser.h | 4 ++-- doc/source_debugging.md | 2 +- wamr-compiler/CMakeLists.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/iwasm/aot/debug/elf_parser.h b/core/iwasm/aot/debug/elf_parser.h index 4e4b9b21..887d82fa 100644 --- a/core/iwasm/aot/debug/elf_parser.h +++ b/core/iwasm/aot/debug/elf_parser.h @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#ifndef _ELF_PARSERE_H_ +#ifndef _ELF_PARSER_H_ #define _ELF_PARSER_H_ #include @@ -24,4 +24,4 @@ get_text_section(void *buf, uint64_t *offset, uint64_t *size); } #endif -#endif \ No newline at end of file +#endif diff --git a/doc/source_debugging.md b/doc/source_debugging.md index f10bbb33..9292d5da 100644 --- a/doc/source_debugging.md +++ b/doc/source_debugging.md @@ -60,7 +60,7 @@ Then you can use lldb commands to debug your applications. Please refer to [lldb 1. Build lldb (assume you have already built llvm) ``` bash cd ${WAMR_ROOT}/core/deps/llvm/build -cmake . -DLLVM_ENABLE_PROJECTS="clang;lldb" +cmake ../llvm -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLDB_INCLUDE_TESTS=OFF make -j $(nproc) ``` diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 2eff9bb6..e3c2de4e 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -151,7 +151,7 @@ if (WAMR_BUILD_DEBUG_AOT EQUAL 1) include_directories(${LLVM_BUILD_BINARY_DIR}/tools/lldb/include) endif() link_directories(${LLVM_LIBRARY_DIRS}) - find_library(lib_lldb NAMES lldb HINTS ${LLVM_LIBRARY_DIRS}) + find_library(lib_lldb NAMES lldb HINTS ${LLVM_LIBRARY_DIRS} REQUIRED) message(STATUS "find lldb ${LLDB_ALL_PLUGINS} in: ${LLVM_LIBRARY_DIRS}") endif() From f5939c7bc1930ecaaa42f5bf332e084753689400 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 16 Sep 2022 19:54:04 +0900 Subject: [PATCH 05/29] Fix AOT debug for macOS (#1494) note: macOS doesn't have elf.h --- ATTRIBUTIONS.md | 8 + core/iwasm/aot/debug/LICENSE_NUTTX | 202 ++++++++++++++++ core/iwasm/aot/debug/NOTICE_NUTTX | 5 + core/iwasm/aot/debug/elf.h | 368 +++++++++++++++++++++++++++++ core/iwasm/aot/debug/elf32.h | 161 +++++++++++++ core/iwasm/aot/debug/elf64.h | 161 +++++++++++++ core/iwasm/aot/debug/elf_parser.c | 2 +- 7 files changed, 906 insertions(+), 1 deletion(-) create mode 100644 core/iwasm/aot/debug/LICENSE_NUTTX create mode 100644 core/iwasm/aot/debug/NOTICE_NUTTX create mode 100644 core/iwasm/aot/debug/elf.h create mode 100644 core/iwasm/aot/debug/elf32.h create mode 100644 core/iwasm/aot/debug/elf64.h diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index bd794793..0cf62f49 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -15,6 +15,7 @@ WAMR project reused some components from other open source project: - **uvwasi**: for the WASI Libc with uvwasi implementation - **asmjit**: for the Fast JIT x86-64 codegen implementation - **zydis**: for the Fast JIT x86-64 codegen implementation +- **NuttX ELF headers**: used in core/iwasm/aot/debug/elf_parser.c The WAMR fast interpreter is a clean room development. We would acknowledge the inspirations by [WASM3](https://github.com/wasm3/wasm3) open source project for the approach of pre-calculated oprand stack location. @@ -33,6 +34,7 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the | uvwasi | unspecified | v0.0.12 | https://github.com/nodejs/uvwasi | | | asmjit | unspecified | unspecified | https://github.com/asmjit/asmjit | | | zydis | unspecified | e14a07895136182a5b53e181eec3b1c6e0b434de | https://github.com/zyantific/zydis | | +| NuttX ELF headers | 72313301e23f9c2de969fb64b9a0f67bb4c284df | 10.3.0 | https://github.com/apache/incubator-nuttx | | ## Licenses @@ -89,3 +91,9 @@ The WAMR fast interpreter is a clean room development. We would acknowledge the ### zydis [LICENSE](./core/iwasm/fast-jit/cg/LICENSE_ZYDIS) + +### NuttX ELF headers + +[LICENSE](./core/iwasm/aot/debug/LICENSE_NUTTX) + +[NOTICE](./core/iwasm/aot/debug/NOTICE_NUTTX) diff --git a/core/iwasm/aot/debug/LICENSE_NUTTX b/core/iwasm/aot/debug/LICENSE_NUTTX new file mode 100644 index 00000000..43fa6abd --- /dev/null +++ b/core/iwasm/aot/debug/LICENSE_NUTTX @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/core/iwasm/aot/debug/NOTICE_NUTTX b/core/iwasm/aot/debug/NOTICE_NUTTX new file mode 100644 index 00000000..17227cb2 --- /dev/null +++ b/core/iwasm/aot/debug/NOTICE_NUTTX @@ -0,0 +1,5 @@ +Apache NuttX +Copyright 2020 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). diff --git a/core/iwasm/aot/debug/elf.h b/core/iwasm/aot/debug/elf.h new file mode 100644 index 00000000..9bdad652 --- /dev/null +++ b/core/iwasm/aot/debug/elf.h @@ -0,0 +1,368 @@ +/**************************************************************************** + * include/elf.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_ELF_H +#define __INCLUDE_ELF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* NOTE: elf64.h and elf32.h refer EI_NIDENT defined above */ + +#include "elf64.h" +#include "elf32.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Values for Elf_Ehdr::e_type */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_LOPROC 0xff00 /* Processor-specific */ +#define ET_HIPROC 0xffff /* Processor-specific */ + +/* Values for Elf_Ehdr::e_machine (most of this were not included in the + * original SCO document but have been gleaned from elsewhere). + */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 486+ */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC64 */ +#define EM_ARM 40 /* ARM */ +#define EM_SH 42 /* SuperH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_H8_300 46 +#define EM_IA_64 50 /* HP/Intel IA-64 */ +#define EM_X86_64 62 /* AMD x86-64 */ +#define EM_S390 22 /* IBM S/390 */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Renesas M32R */ +#define EM_XTENSA 94 /* Tensilica Xtensa */ +#define EM_RISCV 243 /* RISC-V */ +#define EM_ALPHA 0x9026 +#define EM_CYGNUS_V850 0x9080 +#define EM_CYGNUS_M32R 0x9041 +#define EM_S390_OLD 0xa390 +#define EM_FRV 0x5441 + +/* Values for Elf_Ehdr::e_version */ + +#define EV_NONE 0 /* Invalid version */ +#define EV_CURRENT 1 /* The current version */ + +/* Table 2. Ehe ELF identifier */ + +#define EI_MAG0 0 /* File identification */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 /* File class */ +#define EI_DATA 5 /* Data encoding */ +#define EI_VERSION 6 /* File version */ +#define EI_OSABI 7 /* OS ABI */ +#define EI_PAD 8 /* Start of padding bytes */ + +/* EI_NIDENT is defined in "Included Files" section */ + +#define EI_MAGIC_SIZE 4 +#define EI_MAGIC \ + { \ + 0x7f, 'E', 'L', 'F' \ + } + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" + +/* Table 3. Values for EI_CLASS */ + +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +/* Table 4. Values for EI_DATA */ + +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB \ + 1 /* Least significant byte occupying the lowest address \ + */ +#define ELFDATA2MSB 2 /* Most significant byte occupying the lowest address */ + +/* Table 6. Values for EI_OSABI */ + +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ +#define ELFOSABI_LINUX ELFOSABI_GNU +/* Compatibility alias. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#ifndef ELF_OSABI +#define ELF_OSABI ELFOSABI_NONE +#endif + +/* Table 7: Special Section Indexes */ + +#define SHN_UNDEF 0 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 + +/* Figure 4-9: Section Types, sh_type */ + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* Figure 4-11: Section Attribute Flags, sh_flags */ + +#define SHF_WRITE 1 +#define SHF_ALLOC 2 +#define SHF_EXECINSTR 4 +#define SHF_MASKPROC 0xf0000000 + +/* Figure 4-16: Symbol Binding, ELF_ST_BIND */ + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +/* Figure 4-17: Symbol Types, ELF_ST_TYPE */ + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +/* Figure 5-2: Segment Types, p_type */ + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* Figure 5-3: Segment Flag Bits, p_flags */ + +#define PF_X 1 /* Execute */ +#define PF_W 2 /* Write */ +#define PF_R 4 /* Read */ +#define PF_MASKPROC 0xf0000000 /* Unspecified */ + +/* Figure 5-10: Dynamic Array Tags, d_tag */ + +#define DT_NULL 0 /* d_un=ignored */ +#define DT_NEEDED 1 /* d_un=d_val */ +#define DT_PLTRELSZ 2 /* d_un=d_val */ +#define DT_PLTGOT 3 /* d_un=d_ptr */ +#define DT_HASH 4 /* d_un=d_ptr */ +#define DT_STRTAB 5 /* d_un=d_ptr */ +#define DT_SYMTAB 6 /* d_un=d_ptr */ +#define DT_RELA 7 /* d_un=d_ptr */ +#define DT_RELASZ 8 /* d_un=d_val */ +#define DT_RELAENT 9 /* d_un=d_val */ +#define DT_STRSZ 10 /* d_un=d_val */ +#define DT_SYMENT 11 /* d_un=d_val */ +#define DT_INIT 12 /* d_un=d_ptr */ +#define DT_FINI 13 /* d_un=d_ptr */ +#define DT_SONAME 14 /* d_un=d_val */ +#define DT_RPATH 15 /* d_un=d_val */ +#define DT_SYMBOLIC 16 /* d_un=ignored */ +#define DT_REL 17 /* d_un=d_ptr */ +#define DT_RELSZ 18 /* d_un=d_val */ +#define DT_RELENT 19 /* d_un=d_val */ +#define DT_PLTREL 20 /* d_un=d_val */ +#define DT_DEBUG 21 /* d_un=d_ptr */ +#define DT_TEXTREL 22 /* d_un=ignored */ +#define DT_JMPREL 23 /* d_un=d_ptr */ +#define DT_BINDNOW 24 /* d_un=ignored */ +#define DT_LOPROC 0x70000000 /* d_un=unspecified */ +#define DT_HIPROC 0x7fffffff /* d_un= unspecified */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_PRFPREG 2 /* Contains copy of fpregset struct. */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ +#define NT_SIGINFO 0x53494749 +/* Contains copy of siginfo_t, + * size might increase + */ +#define NT_FILE 0x46494c45 +/* Contains information about mapped + * files + */ +#define NT_PRXFPREG 0x46e62b7f +/* Contains copy of user_fxsr_struct */ +#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ +#define NT_PPC_TAR 0x103 /* Target Address Register */ +#define NT_PPC_PPR 0x104 /* Program Priority Register */ +#define NT_PPC_DSCR 0x105 /* Data Stream Control Register */ +#define NT_PPC_EBB 0x106 /* Event Based Branch Registers */ +#define NT_PPC_PMU 0x107 /* Performance Monitor Registers */ +#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */ +#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */ +#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */ +#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */ +#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ +#define NT_PPC_TM_CTAR \ + 0x10d /* TM checkpointed Target Address \ + * Register \ + */ +#define NT_PPC_TM_CPPR \ + 0x10e /* TM checkpointed Program Priority \ + * Register \ + */ +#define NT_PPC_TM_CDSCR \ + 0x10f /* TM checkpointed Data Stream Control \ + * Register \ + */ +#define NT_PPC_PKEY \ + 0x110 /* Memory Protection Keys \ + * registers. \ + */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ +#define NT_S390_TIMER 0x301 /* s390 timer register */ +#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ +#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ +#define NT_S390_CTRS 0x304 /* s390 control registers */ +#define NT_S390_PREFIX 0x305 /* s390 prefix register */ +#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ +#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ +#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ +#define NT_S390_VXRS_LOW \ + 0x309 /* s390 vector registers 0-15 \ + * upper half. \ + */ +#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31. */ +#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers. */ +#define NT_S390_GS_BC \ + 0x30c /* s390 guarded storage \ + * broadcast control block. \ + */ +#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation. */ +#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ +#define NT_ARM_TLS 0x401 /* ARM TLS register */ +#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ +#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ +#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ +#define NT_ARM_SVE \ + 0x405 /* ARM Scalable Vector Extension \ + * registers \ + */ +#define NT_ARM_PAC_MASK \ + 0x406 /* ARM pointer authentication \ + * code masks. \ + */ +#define NT_ARM_PACA_KEYS \ + 0x407 /* ARM pointer authentication \ + * address keys. \ + */ +#define NT_ARM_PACG_KEYS \ + 0x408 /* ARM pointer authentication \ + * generic key. \ + */ +#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note. */ +#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers. */ +#define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode. */ +#define NT_MIPS_MSA 0x802 /* MIPS SIMD registers. */ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + +#endif /* __INCLUDE_ELF_H */ diff --git a/core/iwasm/aot/debug/elf32.h b/core/iwasm/aot/debug/elf32.h new file mode 100644 index 00000000..b4b27948 --- /dev/null +++ b/core/iwasm/aot/debug/elf32.h @@ -0,0 +1,161 @@ +/**************************************************************************** + * include/elf32.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_ELF32_H +#define __INCLUDE_ELF32_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b, t) (((b) << 4) | ((t)&0xf)) + +/* Definitions for Elf32_Rel*::r_info */ + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((i)&0xff) +#define ELF32_R_INFO(s, t) (((s) << 8) | ((t)&0xff)) + +#if 0 +#define ELF_R_SYM(i) ELF32_R_SYM(i) +#endif + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* Figure 4.2: 32-Bit Data Types */ + +typedef uint32_t Elf32_Addr; /* Unsigned program address */ +typedef uint16_t Elf32_Half; /* Unsigned medium integer */ +typedef uint32_t Elf32_Off; /* Unsigned file offset */ +typedef int32_t Elf32_Sword; /* Signed large integer */ +typedef uint32_t Elf32_Word; /* Unsigned large integer */ + +/* Figure 4-3: ELF Header */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +/* Figure 4-8: Section Header */ + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +/* Figure 4-15: Symbol Table Entry */ + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +/* Figure 4-19: Relocation Entries */ + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +/* Figure 5-1: Program Header */ + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +/* Figure 5-7: Note Information */ + +typedef struct { + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +/* Figure 5-9: Dynamic Structure */ + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +#if 0 +typedef Elf32_Addr Elf_Addr; +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Rel Elf_Rel; +typedef Elf32_Rela Elf_Rela; +typedef Elf32_Nhdr Elf_Nhdr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Sym Elf_Sym; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Word Elf_Word; +#endif + +#endif /* __INCLUDE_ELF32_H */ diff --git a/core/iwasm/aot/debug/elf64.h b/core/iwasm/aot/debug/elf64.h new file mode 100644 index 00000000..499c737c --- /dev/null +++ b/core/iwasm/aot/debug/elf64.h @@ -0,0 +1,161 @@ +/**************************************************************************** + * include/elf64.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_ELF64_H +#define __INCLUDE_ELF64_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* See ELF-64 Object File Format: Version 1.5 Draft 2 */ + +/* Definitions for Elf64_Rel*::r_info */ + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffffL) +#define ELF64_R_INFO(s, t) (((s) << 32) + ((t)&0xffffffffL)) + +#if 0 +#define ELF_R_SYM(i) ELF64_R_SYM(i) +#endif + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* Table 1: ELF-64 Data Types */ + +typedef uint64_t Elf64_Addr; /* Unsigned program address */ +typedef uint64_t Elf64_Off; /* Unsigned file offset */ +typedef uint16_t Elf64_Half; /* Unsigned medium integer */ +typedef uint32_t Elf64_Word; /* Unsigned long integer */ +typedef int32_t Elf64_Sword; /* Signed integer */ +typedef uint64_t Elf64_Xword; /* Unsigned long integer */ +typedef int64_t Elf64_Sxword; /* Signed large integer */ + +/* Figure 2: ELF-64 Header */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Machine type */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point address */ + Elf64_Off e_phoff; /* Program header offset */ + Elf64_Off e_shoff; /* Section header offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size */ + Elf64_Half e_phentsize; /* Size of program header entry */ + Elf64_Half e_phnum; /* Number of program header entry */ + Elf64_Half e_shentsize; /* Size of section header entry */ + Elf64_Half e_shnum; /* Number of section header entries */ + Elf64_Half e_shstrndx; /* Section name string table index */ +} Elf64_Ehdr; + +/* Figure 3: ELF-64 Section Header */ + +typedef struct { + Elf64_Word sh_name; /* Section name */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section attributes */ + Elf64_Addr sh_addr; /* Virtual address in memory */ + Elf64_Off sh_offset; /* Offset in file */ + Elf64_Xword sh_size; /* Size of section */ + Elf64_Word sh_link; /* Link to other section */ + Elf64_Word sh_info; /* Miscellaneous information */ + Elf64_Xword sh_addralign; /* Address alignment boundary */ + Elf64_Xword sh_entsize; /* Size of entries, if section has table */ +} Elf64_Shdr; + +/* Figure 4: ELF-64 Symbol Table Entry */ + +typedef struct { + Elf64_Word st_name; /* Symbol name */ + unsigned char st_info; /* Type and Binding attributes */ + unsigned char st_other; /* Reserved */ + Elf64_Half st_shndx; /* Section table index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Size of object (e.g., common) */ +} Elf64_Sym; + +/* Figure 5: ELF-64 Relocation Entries */ + +typedef struct { + Elf64_Addr r_offset; /* Address of reference */ + Elf64_Xword r_info; /* Symbol index and type of relocation */ +} Elf64_Rel; + +typedef struct { + Elf64_Addr r_offset; /* Address of reference */ + Elf64_Xword r_info; /* Symbol index and type of relocation */ + Elf64_Sxword r_addend; /* Constant part of expression */ +} Elf64_Rela; + +/* Figure 6: ELF-64 Program Header Table Entry */ + +typedef struct { + Elf64_Word p_type; /* Type of segment */ + Elf64_Word p_flags; /* Segment attributes */ + Elf64_Off p_offset; /* Offset in file */ + Elf64_Addr p_vaddr; /* Virtual address in memory */ + Elf64_Addr p_paddr; /* Reserved */ + Elf64_Word p_filesz; /* Size of segment in file */ + Elf64_Word p_memsz; /* Size of segment in memory */ + Elf64_Word p_align; /* Alignment of segment */ +} Elf64_Phdr; + +/* Figure 7. Format of a Note Section */ + +typedef struct { + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Figure 8: Dynamic Table Structure */ + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +#if 0 +typedef Elf64_Addr Elf_Addr; +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Rel Elf_Rel; +typedef Elf64_Rela Elf_Rela; +typedef Elf64_Nhdr Elf_Nhdr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Sym Elf_Sym; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Word Elf_Word; +#endif + +#endif /* __INCLUDE_ELF64_H */ diff --git a/core/iwasm/aot/debug/elf_parser.c b/core/iwasm/aot/debug/elf_parser.c index 2fe3e11f..9fec281d 100644 --- a/core/iwasm/aot/debug/elf_parser.c +++ b/core/iwasm/aot/debug/elf_parser.c @@ -12,7 +12,7 @@ #include #include -#include +#include "elf.h" #include "aot_runtime.h" #include "bh_log.h" From 12bbb9189cfb0f9094f7f60d0b69ece48cd46a46 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Sat, 17 Sep 2022 22:01:29 +0900 Subject: [PATCH 06/29] source_debugging.md: Add some notes about AOT debug (#1496) --- doc/source_debugging.md | 68 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/doc/source_debugging.md b/doc/source_debugging.md index 9292d5da..a07cebc4 100644 --- a/doc/source_debugging.md +++ b/doc/source_debugging.md @@ -86,11 +86,71 @@ wamrc -o test.aot test.wasm ``` 5. Execute iwasm using lldb -``` bash -lldb-12 iwasm -- test.aot -``` -Then you can use lldb commands to debug both wamr runtime and your wasm application in ***current terminal*** + Then you can use lldb commands to debug both wamr runtime and your wasm application in ***current terminal***. + + ``` bash + % lldb iwasm -- test.aot + (lldb) target create "iwasm" + Current executable set to 'iwasm' (x86_64). + (lldb) settings set -- target.run-args "test.aot" + (lldb) settings set plugin.jit-loader.gdb.enable on + (lldb) b main + Breakpoint 1: where = iwasm`main + 48 at main.c:294:11, address = 0x0000000100001020 + (lldb) run + Process 27954 launched: '/tmp/bin/iwasm' (x86_64) + Process 27954 stopped + * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 + frame #0: 0x0000000100001020 iwasm`main(argc=2, argv=0x00007ff7bfeff678) at main.c:294:11 + 291 int + 292 main(int argc, char *argv[]) + 293 { + -> 294 int32 ret = -1; + 295 char *wasm_file = NULL; + 296 const char *func_name = NULL; + 297 uint8 *wasm_file_buf = NULL; + Target 0: (iwasm) stopped. + (lldb) c + Process 27954 resuming + 1 location added to breakpoint 1 + error: need to add support for DW_TAG_base_type 'void' encoded with DW_ATE = 0x0, bit_size = 0 + Process 27954 stopped + * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2 + frame #0: 0x00000001002980a0 JIT(0x100298004)`main(exenv=0x0000000301808200) at hello.c:6:9 + 3 int + 4 main(void) + 5 { + -> 6 printf("hello\n"); + 7 + 8 return 0; + 9 } + Target 0: (iwasm) stopped. + (lldb) br l + Current breakpoints: + 1: name = 'main', locations = 2, resolved = 2, hit count = 2 + 1.1: where = iwasm`main + 48 at main.c:294:11, address = 0x0000000100001020, resolved, hit count = 1 + 1.2: where = JIT(0x100298004)`main + 12 at hello.c:6:9, address = 0x00000001002980a0, resolved, hit count = 1 + + (lldb) + ``` + + * In the above example, + + * The first `main` function, which is in `main.c`, is the main + function of the iwasm command. + + * The second `main` function, which is in `hello.c`, is the main + function of the AOT-compiled wasm module. + + * WAMR AOT debugging uses the GDB JIT loader mechanism to load + the debug info of the debugee module. + On some platforms including macOS, you need to enable it explicitly. + (`settings set plugin.jit-loader.gdb.enable on`) + + References: + + * https://github.com/llvm/llvm-project/blob/main/llvm/docs/DebuggingJITedCode.rst + * https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html ## Enable debugging in embedders (for interpreter) From 046f5f221295be93ee124b7f0fdd047861c1f15c Mon Sep 17 00:00:00 2001 From: Daniel Ludwig Date: Sat, 17 Sep 2022 15:16:38 +0200 Subject: [PATCH 07/29] Fix Windows/MSVC build issues (#1498) Fix two issues of building WAMR on Windows: - The build_llvm.py script calls itself, spawning instances faster than they expire, which makes Python3 eat up the entire RAM in a pretty short time. - The MSVC compiler doesn't support preprocessor statements inside macro expressions. Two places inside bh_assert() were found. --- core/iwasm/aot/aot_runtime.c | 10 +++++++--- core/iwasm/interpreter/wasm_runtime.c | 22 +++++++++++++--------- wamr-compiler/build_llvm.py | 2 +- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index e915bbd3..ddafd918 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -244,14 +244,18 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, tbl_inst = aot_get_table_inst(module_inst, table_seg->table_index); bh_assert(tbl_inst); +#if WASM_ENABLE_REF_TYPES != 0 bh_assert( table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL -#if WASM_ENABLE_REF_TYPES != 0 || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST - || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST + || table_seg->offset.init_expr_type + == INIT_EXPR_TYPE_REFNULL_CONST); +#else + bh_assert(table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + || table_seg->offset.init_expr_type + == INIT_EXPR_TYPE_GET_GLOBAL); #endif - ); /* Resolve table data base offset */ if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 065ef113..f76cccda 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1587,17 +1587,21 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, #endif /* init vec(funcidx) or vec(expr) */ - bh_assert( - table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST - || table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL #if WASM_ENABLE_REF_TYPES != 0 - || table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_FUNCREF_CONST - || table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_REFNULL_CONST + bh_assert(table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_I32_CONST + || table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_GET_GLOBAL + || table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_FUNCREF_CONST + || table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_REFNULL_CONST); +#else + bh_assert(table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_I32_CONST + || table_seg->base_offset.init_expr_type + == INIT_EXPR_TYPE_GET_GLOBAL); #endif - ); if (table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { diff --git a/wamr-compiler/build_llvm.py b/wamr-compiler/build_llvm.py index dd181b81..6597f61a 100644 --- a/wamr-compiler/build_llvm.py +++ b/wamr-compiler/build_llvm.py @@ -11,4 +11,4 @@ import sys script = ( pathlib.Path(__file__).parent.joinpath("../build-scripts/build_llvm.py").resolve() ) -subprocess.check_call([sys.executable, script.name]) +subprocess.check_call([sys.executable, script]) From 64c0b15c52ab00dbb8594f87ba4d59b3f14e2300 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 20 Sep 2022 12:40:24 +0800 Subject: [PATCH 08/29] loader: Sub local count can be 0 (#1504) Sub local count is allowed to be 0 in each group of function local types. --- core/iwasm/interpreter/wasm_loader.c | 4 ++-- core/iwasm/interpreter/wasm_mini_loader.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index e424ebca..ab22d294 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1950,8 +1950,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, local_type_index = 0; for (j = 0; j < local_set_count; j++) { read_leb_uint32(p_code, buf_code_end, sub_local_count); - if (!sub_local_count - || local_type_index > UINT32_MAX - sub_local_count + /* Note: sub_local_count is allowed to be 0 */ + if (local_type_index > UINT32_MAX - sub_local_count || local_type_index + sub_local_count > local_count) { set_error_buf(error_buf, error_buf_size, "invalid local count"); diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index fab97dbd..a2f58956 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1013,8 +1013,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, local_type_index = 0; for (j = 0; j < local_set_count; j++) { read_leb_uint32(p_code, buf_code_end, sub_local_count); - bh_assert(sub_local_count - && local_type_index <= UINT32_MAX - sub_local_count + /* Note: sub_local_count is allowed to be 0 */ + bh_assert(local_type_index <= UINT32_MAX - sub_local_count && local_type_index + sub_local_count <= local_count); CHECK_BUF(p_code, buf_code_end, 1); From ab3ad535ab45cf79eb4df91e19d430a8f4d1cb27 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 20 Sep 2022 15:43:29 +0900 Subject: [PATCH 09/29] core/iwasm/compilation/debug/dwarf_extractor.cpp: remove dead code (#1507) Remove an unused function, dwarf_get_func_info, which is also seemingly incomplete. --- core/iwasm/compilation/debug/dwarf_extractor.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/core/iwasm/compilation/debug/dwarf_extractor.cpp b/core/iwasm/compilation/debug/dwarf_extractor.cpp index cb30a4f6..d5a1be85 100644 --- a/core/iwasm/compilation/debug/dwarf_extractor.cpp +++ b/core/iwasm/compilation/debug/dwarf_extractor.cpp @@ -214,19 +214,6 @@ dwarf_gen_comp_unit_info(AOTCompContext *comp_ctx) return comp_unit; } -bool -dwarf_get_func_info(dwar_extractor_handle_t handle, uint64_t offset) -{ - dwar_extractor *extractor = TO_EXTACTOR(handle); - auto sbaddr = extractor->target.ResolveFileAddress(offset); - SBSymbolContext sc(sbaddr.GetSymbolContext(eSymbolContextFunction)); - if (sc.IsValid()) { - SBFunction function(sc.GetFunction()); - if (function.IsValid()) { - } - } -} - static LLVMDWARFTypeEncoding lldb_get_basic_type_encoding(BasicType basic_type) { @@ -520,4 +507,4 @@ dwarf_gen_func_ret_location(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) location_info = dwarf_gen_location(comp_ctx, func_ctx, vm_offset); return location_info; -} \ No newline at end of file +} From aba37075297b9f3c1a6277bf64c32b0d18ac9d03 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 20 Sep 2022 18:54:50 +0900 Subject: [PATCH 10/29] build_llvm.sh: enable to pass through arguments (#1506) To make it simpler to specify `--project`. --- product-mini/platforms/android/build_llvm.sh | 2 +- product-mini/platforms/darwin/build_llvm.sh | 2 +- product-mini/platforms/linux/build_llvm.sh | 2 +- wamr-compiler/build_llvm.sh | 2 +- wamr-compiler/build_llvm_arc.sh | 2 +- wamr-compiler/build_llvm_xtensa.sh | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/product-mini/platforms/android/build_llvm.sh b/product-mini/platforms/android/build_llvm.sh index dd4fc090..3ef343f9 100755 --- a/product-mini/platforms/android/build_llvm.sh +++ b/product-mini/platforms/android/build_llvm.sh @@ -3,4 +3,4 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -/usr/bin/env python3 ../../../build-scripts/build_llvm.py --platform android +/usr/bin/env python3 ../../../build-scripts/build_llvm.py --platform android "$@" diff --git a/product-mini/platforms/darwin/build_llvm.sh b/product-mini/platforms/darwin/build_llvm.sh index f037b4ff..1cb00425 100755 --- a/product-mini/platforms/darwin/build_llvm.sh +++ b/product-mini/platforms/darwin/build_llvm.sh @@ -3,4 +3,4 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -/usr/bin/env python3 ../../../build-scripts/build_llvm.py --platform darwin +/usr/bin/env python3 ../../../build-scripts/build_llvm.py --platform darwin "$@" diff --git a/product-mini/platforms/linux/build_llvm.sh b/product-mini/platforms/linux/build_llvm.sh index 70371529..47387a3c 100755 --- a/product-mini/platforms/linux/build_llvm.sh +++ b/product-mini/platforms/linux/build_llvm.sh @@ -3,4 +3,4 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -/usr/bin/env python3 ../../../build-scripts/build_llvm.py +/usr/bin/env python3 ../../../build-scripts/build_llvm.py "$@" diff --git a/wamr-compiler/build_llvm.sh b/wamr-compiler/build_llvm.sh index 089e48b2..35dc35ed 100755 --- a/wamr-compiler/build_llvm.sh +++ b/wamr-compiler/build_llvm.sh @@ -3,4 +3,4 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -/usr/bin/env python3 ../build-scripts/build_llvm.py +/usr/bin/env python3 ../build-scripts/build_llvm.py "$@" diff --git a/wamr-compiler/build_llvm_arc.sh b/wamr-compiler/build_llvm_arc.sh index c48c3095..f8f40edd 100755 --- a/wamr-compiler/build_llvm_arc.sh +++ b/wamr-compiler/build_llvm_arc.sh @@ -3,4 +3,4 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -/usr/bin/env python3 ../build-scripts/build_llvm.py --platform arc +/usr/bin/env python3 ../build-scripts/build_llvm.py --platform arc "$@" diff --git a/wamr-compiler/build_llvm_xtensa.sh b/wamr-compiler/build_llvm_xtensa.sh index 8277f9ca..d75b62fe 100755 --- a/wamr-compiler/build_llvm_xtensa.sh +++ b/wamr-compiler/build_llvm_xtensa.sh @@ -3,4 +3,4 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -/usr/bin/env python3 ../build-scripts/build_llvm.py --platform xtensa +/usr/bin/env python3 ../build-scripts/build_llvm.py --platform xtensa "$@" From ba3af0b1965a87dd4a266a4cd29043e9dfdcf625 Mon Sep 17 00:00:00 2001 From: Shengyun Zhou Date: Tue, 20 Sep 2022 20:47:17 +0800 Subject: [PATCH 11/29] AOT: fix crash in dumping call stack when the AOT file doesn't contain custom name section (#1508) --- core/iwasm/aot/aot_runtime.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index ddafd918..c0e4e3e2 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -2920,6 +2920,9 @@ lookup_func_name(const char **func_names, uint32 *func_indexes, int64 low = 0, mid; int64 high = func_index_count - 1; + if (!func_names || !func_indexes || func_index_count == 0) + return NULL; + while (low <= high) { mid = (low + high) / 2; if (func_index == func_indexes[mid]) { From ee210d019f459628d8b465f6f2b9d94b4763f6ee Mon Sep 17 00:00:00 2001 From: TianlongLiang <111852609+TianlongLiang@users.noreply.github.com> Date: Thu, 22 Sep 2022 13:06:11 +0800 Subject: [PATCH 12/29] Dockerfile lint errors fix (#1493) Fix the Dockerfile linter errors and most warnings --- .devcontainer/Dockerfile | 92 ++++++++++--------- README.md | 1 + ci/Dockerfile | 92 ------------------- ci/build_wamr.sh | 2 +- doc/devcontainer.md | 25 +++++ .../platforms/zephyr/simple/Dockerfile | 37 -------- samples/workload/docker/build_workload.sh | 2 +- .../IoT-APP-Store-Demo/wasm_django/Dockerfile | 4 +- .../wasm_django/server/Dockerfile | 2 +- .../WASM-Debug-Server/Docker/Dockerfile | 11 ++- .../wamr-ide/WASM-Toolchain/Docker/Dockerfile | 25 ++--- 11 files changed, 102 insertions(+), 191 deletions(-) delete mode 100644 ci/Dockerfile create mode 100644 doc/devcontainer.md delete mode 100644 product-mini/platforms/zephyr/simple/Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 801cc55e..89249f1b 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -9,29 +9,35 @@ FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT} ARG DEBIAN_FRONTEND=noninteractive ENV TZ=Asian/Shanghai -RUN apt update \ - && apt install -y apt-transport-https apt-utils build-essential \ +RUN apt-get update \ + && apt-get install -y apt-transport-https apt-utils build-essential \ ca-certificates curl g++-multilib git gnupg \ libgcc-9-dev lib32gcc-9-dev lsb-release \ ninja-build ocaml ocamlbuild python2.7 \ software-properties-common tree tzdata \ - unzip valgrind vim wget zip + unzip valgrind vim wget zip --no-install-recommends \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* # # CMAKE (https://apt.kitware.com/) -RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \ +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +RUN wget --progress=dot:giga -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \ && echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null \ - && apt update \ + && apt-get update \ && rm /usr/share/keyrings/kitware-archive-keyring.gpg \ - && apt install -y kitware-archive-keyring \ - && apt install -y cmake + && apt-get install -y kitware-archive-keyring --no-install-recommends \ + && apt-get install -y cmake --no-install-recommends \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* # # install emsdk -RUN cd /opt \ - && git clone https://github.com/emscripten-core/emsdk.git -RUN cd /opt/emsdk \ - && git pull \ +WORKDIR /opt +RUN git clone https://github.com/emscripten-core/emsdk.git + +WORKDIR /opt/emsdk +RUN git pull \ && ./emsdk install 2.0.26 \ && ./emsdk activate 2.0.26 \ && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc @@ -39,60 +45,64 @@ RUN cd /opt/emsdk \ # # install wasi-sdk ARG WASI_SDK_VER=16 -RUN wget -c https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt -RUN tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \ - && ln -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk -RUN rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz +RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt \ + && tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \ + && ln -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ + && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz # #install wabt ARG WABT_VER=1.0.29 -RUN wget -c https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz -P /opt -RUN tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \ - && ln -fs /opt/wabt-${WABT_VER} /opt/wabt -RUN rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz +RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz -P /opt \ + && tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \ + && ln -fs /opt/wabt-${WABT_VER} /opt/wabt \ + && rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz # # install bazelisk ARG BAZELISK_VER=1.12.0 -RUN mkdir /opt/bazelisk -RUN wget -c https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 -P /opt/bazelisk -RUN chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \ +RUN mkdir /opt/bazelisk \ + && wget -c --progress=dot:giga https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 -P /opt/bazelisk \ + && chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \ && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel # # install clang+llvm -RUN cd /etc/apt/apt.conf.d \ - && touch 99verfiy-peer.conf \ +WORKDIR /etc/apt/apt.conf.d +RUN touch 99verfiy-peer.conf \ && echo "Acquire { https::Verify-Peer false }" > 99verfiy-peer.conf -RUN cd /tmp \ - && wget https://apt.llvm.org/llvm.sh \ - && chmod a+x ./llvm.sh -RUN /tmp/llvm.sh 12 all -RUN ln -sf /usr/bin/clang-format-12 /usr/bin/clang-format + +WORKDIR /tmp +RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \ + && chmod a+x ./llvm.sh \ + && /tmp/llvm.sh 12 all \ + && ln -sf /usr/bin/clang-format-12 /usr/bin/clang-format \ + && rm -rf /tmp/* # # [Optional] # # Install pip -RUN apt update && apt install -y --reinstall python3-venv python3-pip -RUN python3 -m pip install --upgrade pip +RUN apt-get update \ + && apt-get install -y --reinstall python3-venv python3-pip --no-install-recommends \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* # # Install required python packages -RUN pip3 install --user black nose pycparser pylint +RUN python3 -m pip install --no-cache-dir --upgrade pip \ + && pip3 install --no-cache-dir --user black nose pycparser pylint -# set path +# set path, PS and clean up ENV PATH "/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" -RUN echo "export PATH=/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" >> /root/.bashrc - -# -# PS -RUN echo "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc - -# Clean up -RUN apt-get autoremove -y \ +RUN echo "export PATH=/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" >> /root/.bashrc \ + && printf "%s\n" "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc \ + && apt-get autoremove -y \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* + +# set workdir when container run +VOLUME /workspace +WORKDIR /workspace \ No newline at end of file diff --git a/README.md b/README.md index 7f419ec3..02f7ea3c 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Getting started - [Build WASM applications](./doc/build_wasm_app.md) - [Port WAMR to a new platform](./doc/port_wamr.md) - [Benchmarks](./tests/benchmarks) and [Samples](./samples) +- [VS Code development container](./doc/devcontainer.md) iwasm VM core ========================= diff --git a/ci/Dockerfile b/ci/Dockerfile deleted file mode 100644 index b6e5af48..00000000 --- a/ci/Dockerfile +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -# tie the ${VARIANT} and a llvm binary release together -# please find a matched version on https://github.com/llvm/llvm-project/releases -ARG VARIANT=focal -FROM ubuntu:${VARIANT} - -ARG DEBIAN_FRONTEND=noninteractive -ENV TZ=Asian/Shanghai - -RUN apt update \ - && apt install -y apt-transport-https apt-utils build-essential \ - ca-certificates curl g++-multilib git gnupg \ - libgcc-9-dev lib32gcc-9-dev lsb-release \ - ninja-build ocaml ocamlbuild python2.7 \ - software-properties-common tree tzdata \ - unzip valgrind vim wget zip - -# -# CMAKE (https://apt.kitware.com/) -RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \ - && echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null \ - && apt update \ - && rm /usr/share/keyrings/kitware-archive-keyring.gpg \ - && apt install -y kitware-archive-keyring \ - && apt install -y cmake - -# -# install emsdk (may not necessary ?) -RUN cd /opt \ - && git clone https://github.com/emscripten-core/emsdk.git -RUN cd /opt/emsdk \ - && git pull \ - && ./emsdk install 2.0.26 \ - && ./emsdk activate 2.0.26 \ - && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc - -# -# install clang and llvm release -ARG CLANG_VER=13.0.0 -RUN wget https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VER}/clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-20.04.tar.xz -P /opt -RUN cd /opt \ - && tar xf clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-20.04.tar.xz \ - && ln -sf clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-20.04 clang-llvm -RUN rm /opt/clang+llvm-${CLANG_VER}-x86_64-linux-gnu-ubuntu-20.04.tar.xz - - -# -# install wasi-sdk -ARG WASI_SDK_VER=14 -RUN wget -c https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VER}/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -P /opt -RUN tar xf /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz -C /opt \ - && ln -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk -RUN rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz - -# -#install wabt -ARG WABT_VER=1.0.24 -RUN wget -c https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/wabt-${WABT_VER}-ubuntu.tar.gz -P /opt -RUN tar xf /opt/wabt-${WABT_VER}-ubuntu.tar.gz -C /opt \ - && ln -fs /opt/wabt-${WABT_VER} /opt/wabt -RUN rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz - -# -# install bazelisk -ARG BAZELISK_VER=1.10.1 -RUN mkdir /opt/bazelisk -RUN wget -c https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VER}/bazelisk-linux-amd64 -P /opt/bazelisk -RUN chmod a+x /opt/bazelisk/bazelisk-linux-amd64 \ - && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel - -# -# install -RUN apt update && apt install -y clang-format - -# set path -ENV PATH "$PATH:/opt/wasi-sdk/bin:/opt/wabt/bin:/opt/binaryen/bin:/opt/bazelisk:/opt/clang-llvm/bin" -RUN echo "export PATH=/opt/wasi-sdk/bin:/opt/wabt/bin:/opt/binaryen/bin:/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" >> /root/.bashrc - -# -# PS -RUN echo "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc - -# Clean up -RUN apt-get autoremove -y \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* \ - && rm -rf /tmp/* - -VOLUME /workspace -WORKDIR /workspace diff --git a/ci/build_wamr.sh b/ci/build_wamr.sh index b7e6c049..2ab42f20 100755 --- a/ci/build_wamr.sh +++ b/ci/build_wamr.sh @@ -9,7 +9,7 @@ readonly VARIANT=$(lsb_release -c | awk '{print $2}') docker build \ --memory=4G --cpu-quota=50000 \ - -t wamr_dev_${VARIANT}:0.1 -f "${CURRENT_PATH}"/Dockerfile "${CURRENT_PATH}" \ + -t wamr_dev_${VARIANT}:0.1 -f "${ROOT}"/.devcontainer/Dockerfile "${ROOT}"/.devcontainer \ && docker run --rm -it \ --cap-add=SYS_PTRACE \ --cpus=".5" \ diff --git a/doc/devcontainer.md b/doc/devcontainer.md new file mode 100644 index 00000000..b75f13ec --- /dev/null +++ b/doc/devcontainer.md @@ -0,0 +1,25 @@ +# Visual Studio Code development container + +We all know Docker containers and may use them a lot in school or work. It resolves dependency management for our projects/applications, prevents package version confusion and conflict, and contamination of the local environment. + +Now WAMR has a Dockerfile under path `.devontainer` to create a container image, dev container images that you could easily use in VS Code. In case you prefer other IDE like Clion, you can also build it and use for the IDE you like. + +## How to use it + +It's straightforward to use Docker in VS Code! First, you have VS Code and Docker installed(if not yet, check [next section](#learn-more-about-docker-and-vs-code) for howto). Then you need to download Docker in VS Code extensions marketplace. + +And that's it, and you are good to go! When you open the root folder of WAMR, in the bottom right corner, the Docker extension will pop a notification and ask if you like to reopen the folder in a container. + +If you encounter any problems or get stuck somewhere, may this video [demo](https://youtu.be/Uvf2FVS1F8k) for docker usage in VS Code will help. + +## Learn more about Docker and VS Code + +[Install Docker](https://docs.docker.com/get-docker/) + +[Install VS Code](https://code.visualstudio.com/) + +[Docker extension for VS Code](https://code.visualstudio.com/docs/containers/overview) + +[Remote development with Docker in VS Code](https://code.visualstudio.com/docs/remote/containers#_getting-started) + +[What is dev container image in VS Code](https://code.visualstudio.com/docs/remote/containers#_prebuilding-dev-container-images) \ No newline at end of file diff --git a/product-mini/platforms/zephyr/simple/Dockerfile b/product-mini/platforms/zephyr/simple/Dockerfile deleted file mode 100644 index 3d8b5161..00000000 --- a/product-mini/platforms/zephyr/simple/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -FROM ubuntu:20.04 - -ARG DOCKER_UID=1000 - -ENV DEBIAN_FRONTEND noninteractive - -RUN apt-get -qq update && apt-get -qq dist-upgrade && apt install -qq -y python3-pip git wget ninja-build - -WORKDIR /tmp - -RUN mkdir /opt/cmake && wget -q https://github.com/Kitware/CMake/releases/download/v3.22.1/cmake-3.22.1-linux-x86_64.sh && sh cmake-3.22.1-linux-x86_64.sh --skip-license --prefix=/opt/cmake && rm cmake-3.22.1-linux-x86_64.sh - -ENV PATH="/opt/cmake/bin:$PATH" - -RUN useradd -m wamr -u ${DOCKER_UID} -G dialout - -USER wamr - -ENV PATH="/home/wamr/.local/bin:$PATH" - -RUN pip3 install --user west - -RUN west init ~/zephyrproject && cd ~/zephyrproject && west update && west zephyr-export - -RUN pip3 install --user -r ~/zephyrproject/zephyr/scripts/requirements.txt - -WORKDIR /home/wamr/zephyrproject - -RUN west espressif install - -ENV ZEPHYR_BASE=/home/wamr/zephyrproject/zephyr -ENV ESPRESSIF_TOOLCHAIN_PATH=/home/wamr/.espressif/tools/zephyr - -WORKDIR /home/wamr/source/product-mini/platforms/zephyr/simple diff --git a/samples/workload/docker/build_workload.sh b/samples/workload/docker/build_workload.sh index 62fe69a9..640cca97 100755 --- a/samples/workload/docker/build_workload.sh +++ b/samples/workload/docker/build_workload.sh @@ -13,7 +13,7 @@ readonly VARIANT=$(lsb_release -c | awk '{print $2}') docker build \ --build-arg VARIANT=${VARIANT} \ --memory 4G --cpu-quota 50000 \ - -t wamr_dev_${VARIANT}:0.1 -f "${ROOT}"/ci/Dockerfile "${ROOT}"/ci && + -t wamr_dev_${VARIANT}:0.1 -f "${ROOT}"/.devcontainer/Dockerfile "${ROOT}"/.devcontainer && docker run --rm -it \ --memory 4G \ --cpus ".5" \ diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile b/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile index 18ca41dc..5430ab8d 100644 --- a/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile @@ -1,9 +1,9 @@ FROM python:3.5 WORKDIR /app -ADD . /app +COPY . /app -RUN pip install django +RUN pip install django --no-cache-dir ENTRYPOINT ["python", "manage.py", "runserver", "0.0.0.0:80"] diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/server/Dockerfile b/test-tools/IoT-APP-Store-Demo/wasm_django/server/Dockerfile index a60caad1..371fa45b 100644 --- a/test-tools/IoT-APP-Store-Demo/wasm_django/server/Dockerfile +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/server/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.5 WORKDIR /app -ADD server/wasm_server.py /app/server/ +COPY server/wasm_server.py /app/server/ ENTRYPOINT ["python", "server/wasm_server.py"] diff --git a/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile b/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile index fd24b0cd..2c4cb5b5 100644 --- a/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile +++ b/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile @@ -8,18 +8,19 @@ WORKDIR /root/ COPY resource /root/ ## - download cmake with wget and set up -RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-linux-x86_64.tar.gz \ +RUN wget --progress=dot:giga https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-linux-x86_64.tar.gz \ && tar -zxvf cmake-3.21.1-linux-x86_64.tar.gz \ && rm -f cmake-3.21.1-linux-x86_64.tar.gz \ && mv cmake-3.21.1-linux-x86_64 /opt/cmake \ && ln -s /opt/cmake/bin/cmake /bin/cmake \ - && apt-get install make + && apt-get -y install make --no-install-recommends ## -clone wamr-repo and build iwasm RUN git clone -b main --depth=1 https://github.com/bytecodealliance/wasm-micro-runtime.git \ - && cd /root/wasm-micro-runtime/product-mini/platforms/linux \ - && mkdir build && cd build \ - && cmake .. -DWAMR_BUILD_DEBUG_INTERP=1 && make \ + && mkdir -p /root/wasm-micro-runtime/product-mini/platforms/linux/build + +WORKDIR /root/wasm-micro-runtime/product-mini/platforms/linux/build +RUN cmake .. -DWAMR_BUILD_DEBUG_INTERP=1 && make \ && cp /root/wasm-micro-runtime/product-mini/platforms/linux/build/iwasm /root/iwasm \ && rm -fr /root/wasm-micro-runtime diff --git a/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile b/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile index 60e7efe6..739b0d14 100644 --- a/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile +++ b/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile @@ -10,12 +10,12 @@ WORKDIR /root/ COPY resource /root/ ## - download cmake with wget and set up -RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-linux-x86_64.tar.gz \ +RUN wget --progress=dot:giga https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-linux-x86_64.tar.gz \ && tar -zxvf cmake-3.21.1-linux-x86_64.tar.gz \ && rm -f cmake-3.21.1-linux-x86_64.tar.gz \ && mv cmake-3.21.1-linux-x86_64 /opt/cmake \ && ln -s /opt/cmake/bin/cmake /bin/cmake \ - && apt-get install make + && apt-get -y install make --no-install-recommends ## set compilation environment for wamrc # - wamr repo @@ -24,19 +24,20 @@ RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1 # - wamr-sdk ## - download wasi-sdk with wget and set up to /opt/wasi-sdk -RUN wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-14/wasi-sdk-14.0-linux.tar.gz \ +RUN wget --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-14/wasi-sdk-14.0-linux.tar.gz \ && tar -zxvf wasi-sdk-14.0-linux.tar.gz \ && mv wasi-sdk-14.0 /opt/wasi-sdk/ \ && rm -f wasi-sdk-14.0-linux.tar.gz ## - clone wamr repo -RUN git clone -b main --depth=1 https://github.com/bytecodealliance/wasm-micro-runtime.git \ - && cd /root/wasm-micro-runtime/wamr-compiler \ - && ./build_llvm.sh \ - && cd /root/wasm-micro-runtime/wamr-compiler \ - && mkdir build \ - && cd build \ - && cmake .. \ +RUN git clone -b main --depth=1 https://github.com/bytecodealliance/wasm-micro-runtime.git + +WORKDIR /root/wasm-micro-runtime/wamr-compiler +RUN ./build_llvm.sh \ + && mkdir build + +WORKDIR /root/wasm-micro-runtime/wamr-compiler/build +RUN cmake .. \ && make \ # - copy the wamrc to /root && cp /root/wasm-micro-runtime/wamr-compiler/build/wamrc /root/wamrc \ @@ -65,6 +66,8 @@ COPY --from=BASE /root/build_wasm.sh ${HOME_DIR} RUN ln -s /opt/cmake/bin/cmake /usr/bin/cmake \ && ln -s ${HOME_DIR}/wamrc /usr/bin/wamrc -RUN apt-get update && apt-get install make +RUN apt-get update && apt-get install -y make --no-install-recommends \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* WORKDIR ${HOME_DIR} From 32d2d169084e7592376b613aaccce1e413b241bb Mon Sep 17 00:00:00 2001 From: Qiang <56512053+FromLiQg@users.noreply.github.com> Date: Thu, 22 Sep 2022 19:37:59 +0800 Subject: [PATCH 13/29] Fix Fast JIT issues reported by instrument test (#1488) - Add checks for `pack_argv` - Fix the checks in creating cc entry/exit basic blocks --- core/iwasm/fast-jit/fe/jit_emit_function.c | 7 ++++++- core/iwasm/fast-jit/jit_ir.c | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/core/iwasm/fast-jit/fe/jit_emit_function.c b/core/iwasm/fast-jit/fe/jit_emit_function.c index 7ba96074..257615f0 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_function.c +++ b/core/iwasm/fast-jit/fe/jit_emit_function.c @@ -262,6 +262,9 @@ pack_argv(JitCompContext *cc) stack_base = cc->total_frame_size + offsetof(WASMInterpFrame, lp); argv = jit_cc_new_reg_ptr(cc); GEN_INSN(ADD, argv, cc->fp_reg, NEW_CONST(PTR, stack_base)); + if (jit_get_last_error(cc)) { + return (JitReg)0; + } return argv; } @@ -341,7 +344,9 @@ jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx, } argv = pack_argv(cc); - + if (!argv) { + goto fail; + } native_ret = jit_cc_new_reg_I32(cc); arg_regs[0] = cc->exec_env_reg; arg_regs[1] = NEW_CONST(I32, tbl_idx); diff --git a/core/iwasm/fast-jit/jit_ir.c b/core/iwasm/fast-jit/jit_ir.c index 31315273..6efc2eff 100644 --- a/core/iwasm/fast-jit/jit_ir.c +++ b/core/iwasm/fast-jit/jit_ir.c @@ -380,9 +380,19 @@ jit_cc_init(JitCompContext *cc, unsigned htab_size) /* Create entry and exit blocks. They must be the first two blocks respectively. */ - if (!(entry_block = jit_cc_new_basic_block(cc, 0)) - || !(exit_block = jit_cc_new_basic_block(cc, 0))) + if (!(entry_block = jit_cc_new_basic_block(cc, 0))) goto fail; + if (!(exit_block = jit_cc_new_basic_block(cc, 0))) { + jit_basic_block_delete(entry_block); + goto fail; + } + + /* Record the entry and exit labels, whose indexes must be 0 and 1 + respectively. */ + cc->entry_label = jit_basic_block_label(entry_block); + cc->exit_label = jit_basic_block_label(exit_block); + bh_assert(jit_reg_no(cc->entry_label) == 0 + && jit_reg_no(cc->exit_label) == 1); if (!(cc->exce_basic_blocks = jit_calloc(sizeof(JitBasicBlock *) * JIT_EXCE_NUM))) @@ -392,13 +402,6 @@ jit_cc_init(JitCompContext *cc, unsigned htab_size) jit_calloc(sizeof(JitIncomingInsnList) * JIT_EXCE_NUM))) goto fail; - /* Record the entry and exit labels, whose indexes must be 0 and 1 - respectively. */ - cc->entry_label = jit_basic_block_label(entry_block); - cc->exit_label = jit_basic_block_label(exit_block); - bh_assert(jit_reg_no(cc->entry_label) == 0 - && jit_reg_no(cc->exit_label) == 1); - cc->hreg_info = jit_codegen_get_hreg_info(); bh_assert(cc->hreg_info->info[JIT_REG_KIND_I32].num > 3); From 78b5c5b484697ced35e320fe7d6e47963b138a17 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 22 Sep 2022 21:46:14 +0800 Subject: [PATCH 14/29] Merge dev/socket into main (#1393) Implement more socket APIs, refer to #1336 and below PRs: - Implement wasi_addr_resolve function (#1319) - Fix socket-api byte order issue when host/network order are the same (#1327) - Enhance sock_addr_local syscall (#1320) - Implement sock_addr_remote syscall (#1360) - Add support for IPv6 in WAMR (#1411) - Implement ns lookup allowlist (#1420) - Implement sock_send_to and sock_recv_from system calls (#1457) - Added http downloader and multicast socket options (#1467) - Fix `bind()` calls to receive the correct size of `sockaddr` structure (#1490) - Assert on correct parameters (#1505) - Copy only received bytes from socket recv buffer into the app buffer (#1497) Co-authored-by: Marcin Kolny Co-authored-by: Marcin Kolny Co-authored-by: Callum Macmillan --- core/iwasm/aot/aot_runtime.c | 8 +- core/iwasm/common/wasm_runtime_common.c | 147 ++- core/iwasm/common/wasm_runtime_common.h | 8 + core/iwasm/include/wasm_export.h | 4 + core/iwasm/interpreter/wasm.h | 2 + core/iwasm/interpreter/wasm_runtime.c | 8 +- core/iwasm/libraries/debug-engine/gdbserver.c | 2 +- .../lib-socket/inc/wasi_socket_ext.h | 627 +++++++++- .../lib-socket/src/wasi/wasi_socket_ext.c | 790 ++++++++++++- .../libraries/libc-wasi/libc_wasi_wrapper.c | 1027 +++++++++++++++-- .../include/wasmtime_ssp.h | 368 +++++- .../sandboxed-system-primitives/src/posix.c | 628 +++++++++- .../sandboxed-system-primitives/src/posix.h | 8 +- .../platform/common/posix/posix_socket.c | 838 +++++++++++++- .../platform/include/platform_api_extension.h | 563 ++++++++- core/shared/platform/linux-sgx/sgx_socket.c | 518 ++++++++- core/shared/platform/linux-sgx/sgx_socket.h | 12 +- core/shared/platform/windows/win_socket.c | 393 ++++++- doc/socket_api.md | 8 + language-bindings/go/wamr/module.go | 13 + product-mini/platforms/posix/main.c | 79 +- samples/socket-api/CMakeLists.txt | 11 + samples/socket-api/README.md | 16 + samples/socket-api/wasm-src/CMakeLists.txt | 4 + samples/socket-api/wasm-src/addr_resolve.c | 69 ++ samples/socket-api/wasm-src/socket_opts.c | 262 +++++ samples/socket-api/wasm-src/socket_utils.h | 48 + samples/socket-api/wasm-src/tcp_client.c | 66 +- samples/socket-api/wasm-src/tcp_server.c | 54 +- samples/socket-api/wasm-src/udp_client.c | 82 ++ samples/socket-api/wasm-src/udp_server.c | 120 ++ 31 files changed, 6345 insertions(+), 438 deletions(-) create mode 100644 samples/socket-api/wasm-src/addr_resolve.c create mode 100644 samples/socket-api/wasm-src/socket_opts.c create mode 100644 samples/socket-api/wasm-src/socket_utils.h create mode 100644 samples/socket-api/wasm-src/udp_client.c create mode 100644 samples/socket-api/wasm-src/udp_server.c diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index c0e4e3e2..0fd805f9 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1061,9 +1061,11 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, 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)) + module->wasi_args.ns_lookup_pool, + module->wasi_args.ns_lookup_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)) goto fail; } #endif diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index f2602959..c1528c58 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2328,12 +2328,8 @@ wasm_runtime_enlarge_memory(WASMModuleInstanceCommon *module, #if WASM_ENABLE_LIBC_WASI != 0 -void -wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], - uint32 dir_count, const char *map_dir_list[], - uint32 map_dir_count, const char *env_list[], - uint32 env_count, char *argv[], int argc, - int stdinfd, int stdoutfd, int stderrfd) +static WASIArguments * +get_wasi_args_from_module(wasm_module_t module) { WASIArguments *wasi_args = NULL; @@ -2346,6 +2342,18 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], wasi_args = &((AOTModule *)module)->wasi_args; #endif + return wasi_args; +} + +void +wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], + uint32 dir_count, const char *map_dir_list[], + uint32 map_dir_count, const char *env_list[], + uint32 env_count, char *argv[], int argc, + int stdinfd, int stdoutfd, int stderrfd) +{ + WASIArguments *wasi_args = get_wasi_args_from_module(module); + if (wasi_args) { wasi_args->dir_list = dir_list; wasi_args->dir_count = dir_count; @@ -2376,16 +2384,7 @@ 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 + WASIArguments *wasi_args = get_wasi_args_from_module(module); if (wasi_args) { wasi_args->addr_pool = addr_pool; @@ -2393,13 +2392,67 @@ wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], } } +void +wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module, + const char *ns_lookup_pool[], + uint32 ns_lookup_pool_size) +{ + WASIArguments *wasi_args = get_wasi_args_from_module(module); + + if (wasi_args) { + wasi_args->ns_lookup_pool = ns_lookup_pool; + wasi_args->ns_lookup_count = ns_lookup_pool_size; + } +} + #if WASM_ENABLE_UVWASI == 0 +static bool +copy_string_array(const char *array[], uint32 array_size, char **buf_ptr, + char ***list_ptr, uint64 *out_buf_size) +{ + uint64 buf_size = 0, total_size; + uint32 buf_offset = 0, i; + char *buf = NULL, **list = NULL; + + for (i = 0; i < array_size; i++) + buf_size += strlen(array[i]) + 1; + + /* We add +1 to generate null-terminated array of strings */ + total_size = sizeof(char *) * (uint64)array_size + 1; + if (total_size >= UINT32_MAX + || (total_size > 0 && !(list = wasm_runtime_malloc((uint32)total_size))) + || buf_size >= UINT32_MAX + || (buf_size > 0 && !(buf = wasm_runtime_malloc((uint32)buf_size)))) { + + if (buf) + wasm_runtime_free(buf); + if (list) + wasm_runtime_free(list); + return false; + } + + for (i = 0; i < array_size; i++) { + list[i] = buf + buf_offset; + bh_strcpy_s(buf + buf_offset, (uint32)buf_size - buf_offset, array[i]); + buf_offset += (uint32)(strlen(array[i]) + 1); + } + list[array_size] = NULL; + + *list_ptr = list; + *buf_ptr = buf; + if (out_buf_size) + *out_buf_size = buf_size; + + return true; +} + 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, const char *addr_pool[], uint32 addr_pool_size, + const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, char *argv[], uint32 argc, int stdinfd, int stdoutfd, int stderrfd, char *error_buf, uint32 error_buf_size) { @@ -2408,8 +2461,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, char **argv_list = NULL; char *env_buf = NULL; char **env_list = NULL; - uint64 argv_buf_size = 0, env_buf_size = 0, total_size; - uint32 argv_buf_offset = 0, env_buf_offset = 0; + char *ns_lookup_buf = NULL; + char **ns_lookup_list = NULL; + uint64 argv_buf_size = 0, env_buf_size = 0; struct fd_table *curfds = NULL; struct fd_prestats *prestats = NULL; struct argv_environ_values *argv_environ = NULL; @@ -2443,50 +2497,20 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, #endif /* process argv[0], trip the path and suffix, only keep the program name */ - for (i = 0; i < argc; i++) - argv_buf_size += strlen(argv[i]) + 1; - - total_size = sizeof(char *) * (uint64)argc; - if (total_size >= UINT32_MAX - || (total_size > 0 - && !(argv_list = wasm_runtime_malloc((uint32)total_size))) - || argv_buf_size >= UINT32_MAX - || (argv_buf_size > 0 - && !(argv_buf = wasm_runtime_malloc((uint32)argv_buf_size)))) { + if (!copy_string_array((const char **)argv, argc, &argv_buf, &argv_list, + &argv_buf_size)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: allocate memory failed"); goto fail; } - for (i = 0; i < argc; i++) { - argv_list[i] = argv_buf + argv_buf_offset; - bh_strcpy_s(argv_buf + argv_buf_offset, - (uint32)argv_buf_size - argv_buf_offset, argv[i]); - argv_buf_offset += (uint32)(strlen(argv[i]) + 1); - } - - for (i = 0; i < env_count; i++) - env_buf_size += strlen(env[i]) + 1; - - total_size = sizeof(char *) * (uint64)env_count; - if (total_size >= UINT32_MAX - || (total_size > 0 - && !(env_list = wasm_runtime_malloc((uint32)total_size))) - || env_buf_size >= UINT32_MAX - || (env_buf_size > 0 - && !(env_buf = wasm_runtime_malloc((uint32)env_buf_size)))) { + if (!copy_string_array(env, env_count, &env_buf, &env_list, + &env_buf_size)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: allocate memory failed"); goto fail; } - for (i = 0; i < env_count; i++) { - env_list[i] = env_buf + env_buf_offset; - bh_strcpy_s(env_buf + env_buf_offset, - (uint32)env_buf_size - env_buf_offset, env[i]); - env_buf_offset += (uint32)(strlen(env[i]) + 1); - } - if (!(curfds = wasm_runtime_malloc(sizeof(struct fd_table))) || !(prestats = wasm_runtime_malloc(sizeof(struct fd_prestats))) || !(argv_environ = @@ -2588,6 +2612,13 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, } } + if (!copy_string_array(ns_lookup_pool, ns_lookup_pool_size, &ns_lookup_buf, + &ns_lookup_list, NULL)) { + set_error_buf(error_buf, error_buf_size, + "Init wasi environment failed: allocate memory failed"); + goto fail; + } + wasi_ctx->curfds = curfds; wasi_ctx->prestats = prestats; wasi_ctx->argv_environ = argv_environ; @@ -2596,6 +2627,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, wasi_ctx->argv_list = argv_list; wasi_ctx->env_buf = env_buf; wasi_ctx->env_list = env_list; + wasi_ctx->ns_lookup_buf = ns_lookup_buf; + wasi_ctx->ns_lookup_list = ns_lookup_list; return true; @@ -2624,6 +2657,10 @@ fail: wasm_runtime_free(env_buf); if (env_list) wasm_runtime_free(env_list); + if (ns_lookup_buf) + wasm_runtime_free(ns_lookup_buf); + if (ns_lookup_list) + wasm_runtime_free(ns_lookup_list); return false; } #else /* else of WASM_ENABLE_UVWASI == 0 */ @@ -2675,6 +2712,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *map_dir_list[], uint32 map_dir_count, const char *env[], uint32 env_count, const char *addr_pool[], uint32 addr_pool_size, + const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, char *argv[], uint32 argc, int stdinfd, int stdoutfd, int stderrfd, char *error_buf, uint32 error_buf_size) { @@ -2851,6 +2889,11 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) wasm_runtime_free(wasi_ctx->env_buf); if (wasi_ctx->env_list) wasm_runtime_free(wasi_ctx->env_list); + if (wasi_ctx->ns_lookup_buf) + wasm_runtime_free(wasi_ctx->ns_lookup_buf); + if (wasi_ctx->ns_lookup_list) + wasm_runtime_free(wasi_ctx->ns_lookup_list); + wasm_runtime_free(wasi_ctx); } } diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 326dc003..6f715274 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -363,6 +363,8 @@ typedef struct WASIContext { struct fd_prestats *prestats; struct argv_environ_values *argv_environ; struct addr_pool *addr_pool; + char *ns_lookup_buf; + char **ns_lookup_list; char *argv_buf; char **argv_list; char *env_buf; @@ -775,6 +777,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *map_dir_list[], uint32 map_dir_count, const char *env[], uint32 env_count, const char *addr_pool[], uint32 addr_pool_size, + const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, char *argv[], uint32 argc, int stdinfd, int stdoutfd, int stderrfd, char *error_buf, uint32 error_buf_size); @@ -791,6 +794,11 @@ 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); + +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module, + const char *ns_lookup_pool[], + uint32 ns_lookup_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 3b8bdb03..bd10a253 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -376,6 +376,10 @@ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], uint32_t addr_pool_size); +WASM_RUNTIME_API_EXTERN void +wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module, const char *ns_lookup_pool[], + uint32_t ns_lookup_pool_size); + /** * Instantiate a WASM module. * diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 07a553d3..44b3973d 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -321,6 +321,8 @@ typedef struct WASIArguments { /* in CIDR noation */ const char **addr_pool; uint32 addr_count; + const char **ns_lookup_pool; + uint32 ns_lookup_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 f76cccda..669852a5 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1701,9 +1701,11 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, 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)) { + module->wasi_args.ns_lookup_pool, + module->wasi_args.ns_lookup_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)) { goto fail; } } diff --git a/core/iwasm/libraries/debug-engine/gdbserver.c b/core/iwasm/libraries/debug-engine/gdbserver.c index eab4ece0..e347cc34 100644 --- a/core/iwasm/libraries/debug-engine/gdbserver.c +++ b/core/iwasm/libraries/debug-engine/gdbserver.c @@ -59,7 +59,7 @@ wasm_create_gdbserver(const char *host, int32 *port) memset(server->receive_ctx, 0, sizeof(rsp_recv_context_t)); - if (0 != os_socket_create(&listen_fd, 1)) { + if (0 != os_socket_create(&listen_fd, true, true)) { LOG_ERROR("wasm gdb server error: create socket failed"); goto fail; } diff --git a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h index 15ec0f51..cad60b11 100644 --- a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h +++ b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h @@ -6,6 +6,7 @@ #ifndef _WASI_SOCKET_EXT_H_ #define _WASI_SOCKET_EXT_H_ +#include #include #include @@ -20,7 +21,12 @@ typedef uint16_t __wasi_ip_port_t; typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t; -/* n0.n1.n2.n3 */ +/* + n0.n1.n2.n3 + Example: + IP Address: 127.0.0.1 + Structure: {n0: 127, n1: 0, n2: 0, n3: 1} +*/ typedef struct __wasi_addr_ip4_t { uint8_t n0; uint8_t n1; @@ -30,9 +36,18 @@ typedef struct __wasi_addr_ip4_t { typedef struct __wasi_addr_ip4_port_t { __wasi_addr_ip4_t addr; - __wasi_ip_port_t port; + __wasi_ip_port_t port; /* host byte order */ } __wasi_addr_ip4_port_t; +/* + n0:n1:n2:n3:h0:h1:h2:h3, each 16bit value uses host byte order + Example (little-endian system) + IP Address fe80::3ba2:893b:4be0:e3dd + Structure: { + n0: 0xfe80, n1:0x0, n2: 0x0, n3: 0x0, + h0: 0x3ba2, h1: 0x893b, h2: 0x4be0, h3: 0xe3dd + } +*/ typedef struct __wasi_addr_ip6_t { uint16_t n0; uint16_t n1; @@ -46,9 +61,17 @@ typedef struct __wasi_addr_ip6_t { typedef struct __wasi_addr_ip6_port_t { __wasi_addr_ip6_t addr; - __wasi_ip_port_t port; + __wasi_ip_port_t port; /* host byte order */ } __wasi_addr_ip6_port_t; +typedef struct __wasi_addr_ip_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_t ip4; + __wasi_addr_ip6_t ip6; + } addr; +} __wasi_addr_ip_t; + typedef struct __wasi_addr_t { __wasi_addr_type_t kind; union { @@ -59,6 +82,18 @@ typedef struct __wasi_addr_t { typedef enum { INET4 = 0, INET6 } __wasi_address_family_t; +typedef struct __wasi_addr_info_t { + __wasi_addr_t addr; + __wasi_sock_type_t type; +} __wasi_addr_info_t; + +typedef struct __wasi_addr_info_hints_t { + __wasi_sock_type_t type; + __wasi_address_family_t family; + // this is to workaround lack of optional parameters + uint8_t hints_enabled; +} __wasi_addr_info_hints_t; + #ifdef __wasi__ /** * Reimplement below POSIX APIs with __wasi_sock_XXX functions. @@ -67,6 +102,43 @@ typedef enum { INET4 = 0, INET6 } __wasi_address_family_t; * * */ +#define SO_REUSEADDR 2 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_LINGER 13 +#define SO_REUSEPORT 15 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +#define TCP_NODELAY 1 +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 +#define TCP_QUICKACK 12 +#define TCP_FASTOPEN_CONNECT 30 + +#define IP_TTL 2 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 + +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_JOIN_GROUP 20 +#define IPV6_LEAVE_GROUP 21 +#define IPV6_V6ONLY 26 + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Protocol family for socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol for socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address for socket. */ + char *ai_canonname; /* Canonical name for service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); @@ -86,8 +158,37 @@ recvmsg(int sockfd, struct msghdr *msg, int flags); ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); +ssize_t +sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); + +ssize_t +recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen); + int socket(int domain, int type, int protocol); + +int +getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +int +getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +int +getsockopt(int sockfd, int level, int optname, void *__restrict optval, + socklen_t *__restrict optlen); + +int +setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen); + +int +getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, + struct addrinfo **res); + +void +freeaddrinfo(struct addrinfo *res); #endif /** @@ -115,16 +216,15 @@ __wasi_sock_accept(__wasi_fd_t fd, __wasi_fd_t *fd_new) * either IP4 or IP6. */ int32_t -__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1, - int32_t arg2) +__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1) __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) +__wasi_sock_addr_local(__wasi_fd_t fd, __wasi_addr_t *addr) { return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_local( - (int32_t)fd, (int32_t)buf, (int32_t)buf_len); + (int32_t)fd, (int32_t)addr); } /** @@ -136,43 +236,49 @@ __wasi_sock_addr_local(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len) * either IP4 or IP6. */ int32_t -__imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1, - int32_t arg2) +__imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1) __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) +__wasi_sock_addr_remote(__wasi_fd_t fd, __wasi_addr_t *addr) { return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_remote( - (int32_t)fd, (int32_t)buf, (int32_t)buf_len); + (int32_t)fd, (int32_t)addr); } /** - * 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. + * Resolve a hostname and a service to one or more IP addresses. Service is + * optional and you can pass empty string in most cases, it is used as 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. + * IPv4 and/or IPv6 addresses. Each address entry consists of a wasi_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 + * This function fills the output buffer as much as possible, truncating the + * entries that didn't fit into the buffer. A number of available addresses + * will be returned through the last parameter. */ int32_t -__imported_wasi_snapshot_preview1_addr_resolve(int32_t arg0, int32_t arg1, - int32_t arg2, int32_t arg3, - int32_t arg4) +__imported_wasi_snapshot_preview1_sock_addr_resolve(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4, int32_t arg5) __attribute__((__import_module__("wasi_snapshot_preview1"), - __import_name__("addr_resolve"))); + __import_name__("sock_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) +__wasi_sock_addr_resolve(const char *host, const char *service, + __wasi_addr_info_hints_t *hints, + __wasi_addr_info_t *addr_info, + __wasi_size_t addr_info_size, + __wasi_size_t *max_info_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); + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_resolve( + (int32_t)host, (int32_t)service, (int32_t)hints, (int32_t)addr_info, + (int32_t)addr_info_size, (int32_t)max_info_size); } /** @@ -191,6 +297,48 @@ __wasi_sock_bind(__wasi_fd_t fd, __wasi_addr_t *addr) (int32_t)fd, (int32_t)addr); } +/** + * Send data to a specific target + * Note: This is similar to `sendto` in POSIX + */ +int32_t +__imported_wasi_snapshot_preview1_sock_send_to(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4, int32_t arg5) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_send_to"))); + +static inline __wasi_errno_t +__wasi_sock_send_to(__wasi_fd_t fd, const __wasi_ciovec_t *si_data, + uint32_t si_data_len, __wasi_siflags_t si_flags, + const __wasi_addr_t *dest_addr, uint32_t *so_data_len) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_send_to( + (int32_t)fd, (int32_t)si_data, (int32_t)si_data_len, (int32_t)si_flags, + (uint32_t)dest_addr, (uint32_t)so_data_len); +} + +/** + * Receives data from a socket + * Note: This is similar to `recvfrom` in POSIX + */ +int32_t +__imported_wasi_snapshot_preview1_sock_recv_from(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4, int32_t arg5) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_recv_from"))); + +static inline __wasi_errno_t +__wasi_sock_recv_from(__wasi_fd_t fd, __wasi_ciovec_t *ri_data, + uint32_t ri_data_len, __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, uint32_t *ro_data_len) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_recv_from( + (int32_t)fd, (int32_t)ri_data, (int32_t)ri_data_len, (int32_t)ri_flags, + (uint32_t)src_addr, (uint32_t)ro_data_len); +} + /** * Close a socket (this is an alias for `fd_close`) * Note: This is similar to `close` in POSIX. @@ -252,7 +400,7 @@ __imported_wasi_snapshot_preview1_sock_get_reuse_addr(int32_t arg0, __import_name__("sock_get_reuse_addr"))); static inline __wasi_errno_t -__wasi_sock_get_reuse_addr(__wasi_fd_t fd, uint8_t *reuse) +__wasi_sock_get_reuse_addr(__wasi_fd_t fd, bool *reuse) { return (__wasi_errno_t) __imported_wasi_snapshot_preview1_sock_get_reuse_addr((int32_t)fd, @@ -270,7 +418,7 @@ __imported_wasi_snapshot_preview1_sock_get_reuse_port(int32_t arg0, __import_name__("sock_get_reuse_port"))); static inline __wasi_errno_t -__wasi_sock_get_reuse_port(__wasi_fd_t fd, int8_t *reuse) +__wasi_sock_get_reuse_port(__wasi_fd_t fd, bool *reuse) { return (__wasi_errno_t) __imported_wasi_snapshot_preview1_sock_get_reuse_port((int32_t)fd, @@ -367,7 +515,7 @@ __imported_wasi_snapshot_preview1_sock_set_reuse_addr(int32_t arg0, __import_name__("sock_set_reuse_addr"))); static inline __wasi_errno_t -__wasi_sock_set_reuse_addr(__wasi_fd_t fd, uint8_t reuse) +__wasi_sock_set_reuse_addr(__wasi_fd_t fd, bool reuse) { return (__wasi_errno_t) __imported_wasi_snapshot_preview1_sock_set_reuse_addr((int32_t)fd, @@ -385,7 +533,7 @@ __imported_wasi_snapshot_preview1_sock_set_reuse_port(int32_t arg0, __import_name__("sock_set_reuse_port"))); static inline __wasi_errno_t -__wasi_sock_set_reuse_port(__wasi_fd_t fd, uint8_t reuse) +__wasi_sock_set_reuse_port(__wasi_fd_t fd, bool reuse) { return (__wasi_errno_t) __imported_wasi_snapshot_preview1_sock_set_reuse_port((int32_t)fd, @@ -397,20 +545,435 @@ __wasi_sock_set_reuse_port(__wasi_fd_t fd, uint8_t reuse) * 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) +__imported_wasi_snapshot_preview1_sock_set_send_buf_size(int32_t arg0, + int32_t arg1) __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) +__wasi_sock_set_send_buf_size(__wasi_fd_t fd, __wasi_size_t buf_len) { return (__wasi_errno_t) - __imported_wasi_snapshot_preview1_sock_set_send_buf_size((int32_t)fd); + __imported_wasi_snapshot_preview1_sock_set_send_buf_size( + (int32_t)fd, (int32_t)buf_len); } +int32_t +__imported_wasi_snapshot_preview1_sock_get_recv_timeout(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_recv_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_get_recv_timeout(__wasi_fd_t fd, uint64_t *timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_recv_timeout( + (int32_t)fd, (int32_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_recv_timeout(int32_t arg0, + int64_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_recv_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_set_recv_timeout(__wasi_fd_t fd, uint64_t timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_recv_timeout( + (int32_t)fd, (int64_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_send_timeout(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_send_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_get_send_timeout(__wasi_fd_t fd, uint64_t *timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_send_timeout( + (int32_t)fd, (int32_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_send_timeout(int32_t arg0, + int64_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_send_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_set_send_timeout(__wasi_fd_t fd, uint64_t timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_send_timeout( + (int32_t)fd, (int64_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_keep_alive(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_keep_alive"))); + +static inline __wasi_errno_t +__wasi_sock_set_keep_alive(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_keep_alive((int32_t)fd, + (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_keep_alive(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_keep_alive"))); + +static inline __wasi_errno_t +__wasi_sock_get_keep_alive(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_keep_alive((int32_t)fd, + (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_linger(int32_t arg0, int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_linger"))); + +static inline __wasi_errno_t +__wasi_sock_set_linger(__wasi_fd_t fd, bool is_enabled, int linger_s) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_linger( + (int32_t)fd, (int32_t)is_enabled, (int32_t)linger_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_linger(int32_t arg0, int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_linger"))); + +static inline __wasi_errno_t +__wasi_sock_get_linger(__wasi_fd_t fd, bool *is_enabled, int *linger_s) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_linger( + (int32_t)fd, (int32_t)is_enabled, (int32_t)linger_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_keep_idle(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_keep_idle"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_keep_idle(__wasi_fd_t fd, uint32_t time_s) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_keep_idle( + (int32_t)fd, (int32_t)time_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_keep_idle(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_keep_idle"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_keep_idle(__wasi_fd_t fd, uint32_t *time_s) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_keep_idle( + (int32_t)fd, (int32_t)time_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_keep_intvl(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_keep_intvl"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_keep_intvl(__wasi_fd_t fd, uint32_t time_s) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_keep_intvl( + (int32_t)fd, (int32_t)time_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_keep_intvl(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_keep_intvl"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_keep_intvl(__wasi_fd_t fd, uint32_t *time_s) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_keep_intvl( + (int32_t)fd, (int32_t)time_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_fastopen_connect(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_fastopen_connect"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_fastopen_connect(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_fastopen_connect( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_fastopen_connect(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_fastopen_connect"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_fastopen_connect(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_fastopen_connect( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_multicast_loop(int32_t arg0, + int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_multicast_loop"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_multicast_loop(__wasi_fd_t fd, bool ipv6, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_ip_multicast_loop( + (int32_t)fd, (int32_t)ipv6, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_ip_multicast_loop(int32_t arg0, + int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_ip_multicast_loop"))); + +static inline __wasi_errno_t +__wasi_sock_get_ip_multicast_loop(__wasi_fd_t fd, bool ipv6, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_ip_multicast_loop( + (int32_t)fd, (int32_t)ipv6, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_multicast_ttl(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_multicast_ttl"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_multicast_ttl(__wasi_fd_t fd, uint8_t option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_ip_multicast_ttl( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_ip_multicast_ttl(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_ip_multicast_ttl"))); + +static inline __wasi_errno_t +__wasi_sock_get_ip_multicast_ttl(__wasi_fd_t fd, uint8_t *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_ip_multicast_ttl( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_add_membership(int32_t arg0, + int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_add_membership"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_add_membership(__wasi_fd_t fd, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_ip_add_membership( + (int32_t)fd, (int32_t)imr_multiaddr, (int32_t)imr_interface); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_drop_membership(int32_t arg0, + int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_drop_membership"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_drop_membership(__wasi_fd_t fd, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_ip_drop_membership( + (int32_t)fd, (int32_t)imr_multiaddr, (int32_t)imr_interface); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_broadcast(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_broadcast"))); + +static inline __wasi_errno_t +__wasi_sock_set_broadcast(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_broadcast( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_broadcast(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_broadcast"))); + +static inline __wasi_errno_t +__wasi_sock_get_broadcast(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_broadcast( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_no_delay(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_no_delay"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_no_delay(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_no_delay( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_no_delay(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_no_delay"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_no_delay(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_no_delay( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_quick_ack(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_quick_ack"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_quick_ack(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_quick_ack( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_quick_ack(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_quick_ack"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_quick_ack(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_quick_ack( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_ttl(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_ttl"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_ttl(__wasi_fd_t fd, uint8_t option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_ip_ttl( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_ip_ttl(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_ip_ttl"))); + +static inline __wasi_errno_t +__wasi_sock_get_ip_ttl(__wasi_fd_t fd, uint8_t *option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_ip_ttl( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ipv6_only(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ipv6_only"))); + +static inline __wasi_errno_t +__wasi_sock_set_ipv6_only(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_ipv6_only( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_ipv6_only(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_ipv6_only"))); + +static inline __wasi_errno_t +__wasi_sock_get_ipv6_only(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_ipv6_only( + (int32_t)fd, (int32_t)option); +} /** * 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 +#endif 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 index a96156f7..aaf658dd 100644 --- a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c +++ b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c @@ -18,16 +18,44 @@ return -1; \ } +static void +ipv4_addr_to_wasi_ip4_addr(uint32_t addr_num, __wasi_addr_ip4_t *out) +{ + addr_num = ntohl(addr_num); + out->n0 = (addr_num & 0xFF000000) >> 24; + out->n1 = (addr_num & 0x00FF0000) >> 16; + out->n2 = (addr_num & 0x0000FF00) >> 8; + out->n3 = (addr_num & 0x000000FF); +} + /* 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); + ipv4_addr_to_wasi_ip4_addr(addr_num, &(out->addr.ip4.addr)); +} + +static void +ipv6_addr_to_wasi_ipv6_addr(uint16_t *addr, __wasi_addr_ip6_t *out) +{ + out->n0 = ntohs(addr[0]); + out->n1 = ntohs(addr[1]); + out->n2 = ntohs(addr[2]); + out->n3 = ntohs(addr[3]); + out->h0 = ntohs(addr[4]); + out->h1 = ntohs(addr[5]); + out->h2 = ntohs(addr[6]); + out->h3 = ntohs(addr[7]); +} + +static void +ipv6_addr_to_wasi_addr(uint16_t *addr, uint16_t port, __wasi_addr_t *out) +{ + out->kind = IPv6; + out->addr.ip6.port = ntohs(port); + ipv6_addr_to_wasi_ipv6_addr(addr, &(out->addr.ip6.addr)); } static __wasi_errno_t @@ -36,15 +64,17 @@ sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen, { __wasi_errno_t ret = __WASI_ERRNO_SUCCESS; if (AF_INET == sock_addr->sa_family) { - assert(sizeof(struct sockaddr_in) == addrlen); + 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; + assert(sizeof(struct sockaddr_in6) <= addrlen); + ipv6_addr_to_wasi_addr( + (uint16_t *)((struct sockaddr_in6 *)sock_addr)->sin6_addr.s6_addr, + ((struct sockaddr_in6 *)sock_addr)->sin6_port, wasi_addr); } else { ret = __WASI_ERRNO_AFNOSUPPORT; @@ -54,38 +84,52 @@ sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen, } static __wasi_errno_t -sock_addr_remote(__wasi_fd_t fd, struct sockaddr *sock_addr, socklen_t *addrlen) +wasi_addr_to_sockaddr(const __wasi_addr_t *wasi_addr, + struct sockaddr *sock_addr, socklen_t *addrlen) { - __wasi_addr_t wasi_addr = { 0 }; - __wasi_errno_t error; + switch (wasi_addr->kind) { + case IPv4: + { + struct sockaddr_in sock_addr_in = { 0 }; + uint32_t s_addr; - error = - __wasi_sock_addr_remote(fd, (uint8_t *)&wasi_addr, sizeof(wasi_addr)); - if (__WASI_ERRNO_SUCCESS != error) { - return error; + s_addr = (wasi_addr->addr.ip4.addr.n0 << 24) + | (wasi_addr->addr.ip4.addr.n1 << 16) + | (wasi_addr->addr.ip4.addr.n2 << 8) + | wasi_addr->addr.ip4.addr.n3; + + sock_addr_in.sin_family = AF_INET; + sock_addr_in.sin_addr.s_addr = htonl(s_addr); + 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); + break; + } + case IPv6: + { + struct sockaddr_in6 sock_addr_in6 = { 0 }; + uint16_t *addr_buf = (uint16_t *)sock_addr_in6.sin6_addr.s6_addr; + + addr_buf[0] = htons(wasi_addr->addr.ip6.addr.n0); + addr_buf[1] = htons(wasi_addr->addr.ip6.addr.n1); + addr_buf[2] = htons(wasi_addr->addr.ip6.addr.n2); + addr_buf[3] = htons(wasi_addr->addr.ip6.addr.n3); + addr_buf[4] = htons(wasi_addr->addr.ip6.addr.h0); + addr_buf[5] = htons(wasi_addr->addr.ip6.addr.h1); + addr_buf[6] = htons(wasi_addr->addr.ip6.addr.h2); + addr_buf[7] = htons(wasi_addr->addr.ip6.addr.h3); + + sock_addr_in6.sin6_family = AF_INET6; + sock_addr_in6.sin6_port = htons(wasi_addr->addr.ip6.port); + memcpy(sock_addr, &sock_addr_in6, sizeof(sock_addr_in6)); + + *addrlen = sizeof(sock_addr_in6); + break; + } + default: + return __WASI_ERRNO_AFNOSUPPORT; } - - 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; } @@ -99,9 +143,8 @@ accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) error = __wasi_sock_accept(sockfd, &new_sockfd); HANDLE_ERROR(error) - // error = sock_addr_remote(new_sockfd, addr, addrlen); - // HANDLE_ERROR(error) - *addrlen = 0; + error = getpeername(new_sockfd, addr, addrlen); + HANDLE_ERROR(error) return new_sockfd; } @@ -221,6 +264,66 @@ sendmsg(int sockfd, const struct msghdr *msg, int flags) return so_datalen; } +ssize_t +sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + // Prepare input parameters. + __wasi_ciovec_t iov = { .buf = buf, .buf_len = len }; + uint32_t so_datalen = 0; + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + size_t si_data_len = 1; + __wasi_siflags_t si_flags = 0; + + // This implementation does not support any flags. + if (flags != 0) { + HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT) + } + + error = sockaddr_to_wasi_addr(dest_addr, addrlen, &wasi_addr); + HANDLE_ERROR(error); + + // Perform system call. + error = __wasi_sock_send_to(sockfd, &iov, si_data_len, si_flags, &wasi_addr, + &so_datalen); + HANDLE_ERROR(error) + + return so_datalen; +} + +ssize_t +recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen) +{ + // Prepare input parameters. + __wasi_ciovec_t iov = { .buf = buf, .buf_len = len }; + uint32_t so_datalen = 0; + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + size_t si_data_len = 1; + __wasi_siflags_t si_flags = 0; + + // This implementation does not support any flags. + if (flags != 0) { + HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT) + } + + if (!src_addr) { + return recv(sockfd, buf, len, flags); + } + + // Perform system call. + error = __wasi_sock_recv_from(sockfd, &iov, si_data_len, si_flags, + &wasi_addr, &so_datalen); + HANDLE_ERROR(error); + + error = wasi_addr_to_sockaddr(&wasi_addr, src_addr, addrlen); + HANDLE_ERROR(error); + + return so_datalen; +} + int socket(int domain, int type, int protocol) { @@ -256,3 +359,612 @@ socket(int domain, int type, int protocol) return sockfd; } + +int +getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + __wasi_addr_t wasi_addr = { 0 }; + __wasi_errno_t error; + + error = __wasi_sock_addr_local(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + error = wasi_addr_to_sockaddr(&wasi_addr, addr, addrlen); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} + +int +getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + __wasi_addr_t wasi_addr = { 0 }; + __wasi_errno_t error; + + error = __wasi_sock_addr_remote(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + error = wasi_addr_to_sockaddr(&wasi_addr, addr, addrlen); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} + +struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; +}; + +static __wasi_errno_t +addrinfo_hints_to_wasi_hints(const struct addrinfo *hints, + __wasi_addr_info_hints_t *wasi_hints) +{ + if (hints) { + wasi_hints->hints_enabled = 1; + + switch (hints->ai_family) { + case AF_INET: + wasi_hints->family = INET4; + break; + case AF_INET6: + wasi_hints->family = INET6; + break; + default: + return __WASI_ERRNO_AFNOSUPPORT; + } + switch (hints->ai_socktype) { + case SOCK_STREAM: + wasi_hints->type = SOCKET_STREAM; + break; + case SOCK_DGRAM: + wasi_hints->type = SOCKET_DGRAM; + break; + default: + return __WASI_ERRNO_NOTSUP; + } + + if (hints->ai_protocol != 0) { + return __WASI_ERRNO_NOTSUP; + } + + if (hints->ai_flags != 0) { + return __WASI_ERRNO_NOTSUP; + } + } + else { + wasi_hints->hints_enabled = 0; + } + + return __WASI_ERRNO_SUCCESS; +} + +static __wasi_errno_t +wasi_addr_info_to_addr_info(const __wasi_addr_info_t *addr_info, + struct addrinfo *ai) +{ + ai->ai_socktype = + addr_info->type == SOCKET_DGRAM ? SOCK_DGRAM : SOCK_STREAM; + ai->ai_protocol = 0; + ai->ai_canonname = NULL; + + if (addr_info->addr.kind == IPv4) { + ai->ai_family = AF_INET; + ai->ai_addrlen = sizeof(struct sockaddr_in); + } + else { + ai->ai_family = AF_INET6; + ai->ai_addrlen = sizeof(struct sockaddr_in6); + } + + return wasi_addr_to_sockaddr(&addr_info->addr, ai->ai_addr, + &ai->ai_addrlen); // TODO err handling +} + +int +getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, + struct addrinfo **res) +{ + __wasi_addr_info_hints_t wasi_hints; + __wasi_addr_info_t *addr_info = NULL; + __wasi_size_t addr_info_size, i; + __wasi_size_t max_info_size = 16; + __wasi_errno_t error; + struct aibuf *aibuf_res; + + error = addrinfo_hints_to_wasi_hints(hints, &wasi_hints); + HANDLE_ERROR(error) + + do { + if (addr_info) + free(addr_info); + + addr_info_size = max_info_size; + addr_info = (__wasi_addr_info_t *)malloc(addr_info_size + * sizeof(__wasi_addr_info_t)); + + if (!addr_info) { + HANDLE_ERROR(__WASI_ERRNO_NOMEM) + } + + error = __wasi_sock_addr_resolve(node, service == NULL ? "" : service, + &wasi_hints, addr_info, addr_info_size, + &max_info_size); + if (error != __WASI_ERRNO_SUCCESS) { + free(addr_info); + HANDLE_ERROR(error); + } + } while (max_info_size > addr_info_size); + + if (addr_info_size == 0) { + free(addr_info); + *res = NULL; + return __WASI_ERRNO_SUCCESS; + } + + aibuf_res = calloc(1, addr_info_size * sizeof(struct aibuf)); + if (!aibuf_res) { + free(addr_info); + HANDLE_ERROR(__WASI_ERRNO_NOMEM) + } + + *res = &aibuf_res[0].ai; + + if (addr_info_size) { + addr_info_size = max_info_size; + } + + for (i = 0; i < addr_info_size; i++) { + struct addrinfo *ai = &aibuf_res[i].ai; + ai->ai_addr = (struct sockaddr *)&aibuf_res[i].sa; + + error = wasi_addr_info_to_addr_info(&addr_info[i], ai); + if (error != __WASI_ERRNO_SUCCESS) { + free(addr_info); + free(aibuf_res); + HANDLE_ERROR(error) + } + ai->ai_next = i == addr_info_size - 1 ? NULL : &aibuf_res[i + 1].ai; + } + + free(addr_info); + + return __WASI_ERRNO_SUCCESS; +} + +void +freeaddrinfo(struct addrinfo *res) +{ + /* res is a pointer to a first field in the first element + * of aibuf array allocated in getaddrinfo, therefore this call + * frees the memory of the entire array. */ + free(res); +} + +struct timeval +time_us_to_timeval(uint64_t time_us) +{ + struct timeval tv; + tv.tv_sec = time_us / 1000000UL; + tv.tv_usec = time_us % 1000000UL; + return tv; +} + +uint64_t +timeval_to_time_us(struct timeval tv) +{ + return (tv.tv_sec * 1000000UL) + tv.tv_usec; +} + +int +get_sol_socket_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + uint64_t timeout_us; + bool is_linger_enabled; + int linger_s; + + switch (optname) { + case SO_RCVTIMEO: + assert(*optlen == sizeof(struct timeval)); + error = __wasi_sock_get_recv_timeout(sockfd, &timeout_us); + HANDLE_ERROR(error); + *(struct timeval *)optval = time_us_to_timeval(timeout_us); + return error; + case SO_SNDTIMEO: + assert(*optlen == sizeof(struct timeval)); + error = __wasi_sock_get_send_timeout(sockfd, &timeout_us); + HANDLE_ERROR(error); + *(struct timeval *)optval = time_us_to_timeval(timeout_us); + return error; + case SO_SNDBUF: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_send_buf_size(sockfd, (size_t *)optval); + HANDLE_ERROR(error); + return error; + case SO_RCVBUF: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_recv_buf_size(sockfd, (size_t *)optval); + HANDLE_ERROR(error); + return error; + case SO_KEEPALIVE: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_keep_alive(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_REUSEADDR: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_reuse_addr(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_REUSEPORT: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_reuse_port(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_LINGER: + assert(*optlen == sizeof(struct linger)); + error = + __wasi_sock_get_linger(sockfd, &is_linger_enabled, &linger_s); + HANDLE_ERROR(error); + ((struct linger *)optval)->l_onoff = (int)is_linger_enabled; + ((struct linger *)optval)->l_linger = linger_s; + return error; + case SO_BROADCAST: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_broadcast(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +get_ipproto_tcp_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + switch (optname) { + case TCP_KEEPIDLE: + assert(*optlen == sizeof(uint32_t)); + error = __wasi_sock_get_tcp_keep_idle(sockfd, (uint32_t *)optval); + HANDLE_ERROR(error); + return error; + case TCP_KEEPINTVL: + assert(*optlen == sizeof(uint32_t)); + error = __wasi_sock_get_tcp_keep_intvl(sockfd, (uint32_t *)optval); + HANDLE_ERROR(error); + return error; + case TCP_FASTOPEN_CONNECT: + assert(*optlen == sizeof(int)); + error = + __wasi_sock_get_tcp_fastopen_connect(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case TCP_NODELAY: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_tcp_no_delay(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case TCP_QUICKACK: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_tcp_quick_ack(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +get_ipproto_ip_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + + switch (optname) { + case IP_MULTICAST_LOOP: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_ip_multicast_loop(sockfd, false, + (bool *)optval); + HANDLE_ERROR(error); + return error; + case IP_TTL: + assert(*optlen == sizeof(uint8_t)); + error = __wasi_sock_get_ip_ttl(sockfd, (uint8_t *)optval); + HANDLE_ERROR(error); + return error; + case IP_MULTICAST_TTL: + assert(*optlen == sizeof(uint8_t)); + error = __wasi_sock_get_ip_multicast_ttl(sockfd, (uint8_t *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +get_ipproto_ipv6_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + + switch (optname) { + case IPV6_V6ONLY: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_ipv6_only(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case IPV6_MULTICAST_LOOP: + assert(*optlen == sizeof(int)); + error = + __wasi_sock_get_ip_multicast_loop(sockfd, true, (bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +getsockopt(int sockfd, int level, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + + switch (level) { + case SOL_SOCKET: + return get_sol_socket_option(sockfd, optname, optval, optlen); + case IPPROTO_TCP: + return get_ipproto_tcp_option(sockfd, optname, optval, optlen); + case IPPROTO_IP: + return get_ipproto_ip_option(sockfd, optname, optval, optlen); + case IPPROTO_IPV6: + return get_ipproto_ipv6_option(sockfd, optname, optval, optlen); + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +set_sol_socket_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + uint64_t timeout_us; + + switch (optname) { + case SO_RCVTIMEO: + assert(optlen == sizeof(struct timeval)); + timeout_us = timeval_to_time_us(*(struct timeval *)optval); + error = __wasi_sock_set_recv_timeout(sockfd, timeout_us); + HANDLE_ERROR(error); + return error; + case SO_SNDTIMEO: + assert(optlen == sizeof(struct timeval)); + timeout_us = timeval_to_time_us(*(struct timeval *)optval); + error = __wasi_sock_set_send_timeout(sockfd, timeout_us); + HANDLE_ERROR(error); + return error; + case SO_SNDBUF: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_send_buf_size(sockfd, *(size_t *)optval); + HANDLE_ERROR(error); + return error; + case SO_RCVBUF: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_recv_buf_size(sockfd, *(size_t *)optval); + HANDLE_ERROR(error); + return error; + case SO_KEEPALIVE: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_keep_alive(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_REUSEADDR: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_reuse_addr(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_REUSEPORT: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_reuse_port(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_LINGER: + assert(optlen == sizeof(struct linger)); + struct linger *linger_opt = ((struct linger *)optval); + error = __wasi_sock_set_linger(sockfd, (bool)linger_opt->l_onoff, + linger_opt->l_linger); + HANDLE_ERROR(error); + return error; + case SO_BROADCAST: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_broadcast(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +set_ipproto_tcp_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + + switch (optname) { + case TCP_NODELAY: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_tcp_no_delay(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case TCP_KEEPIDLE: + assert(optlen == sizeof(uint32_t)); + error = __wasi_sock_set_tcp_keep_idle(sockfd, *(uint32_t *)optval); + HANDLE_ERROR(error); + return error; + case TCP_KEEPINTVL: + assert(optlen == sizeof(uint32_t)); + error = __wasi_sock_set_tcp_keep_intvl(sockfd, *(uint32_t *)optval); + HANDLE_ERROR(error); + return error; + case TCP_FASTOPEN_CONNECT: + assert(optlen == sizeof(int)); + error = + __wasi_sock_set_tcp_fastopen_connect(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case TCP_QUICKACK: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_tcp_quick_ack(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +set_ipproto_ip_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + __wasi_addr_ip_t imr_multiaddr; + struct ip_mreq *ip_mreq_opt; + + switch (optname) { + case IP_MULTICAST_LOOP: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_ip_multicast_loop(sockfd, false, + *(bool *)optval); + HANDLE_ERROR(error); + return error; + case IP_ADD_MEMBERSHIP: + assert(optlen == sizeof(struct ip_mreq)); + ip_mreq_opt = (struct ip_mreq *)optval; + imr_multiaddr.kind = IPv4; + ipv4_addr_to_wasi_ip4_addr(ip_mreq_opt->imr_multiaddr.s_addr, + &imr_multiaddr.addr.ip4); + error = __wasi_sock_set_ip_add_membership( + sockfd, &imr_multiaddr, ip_mreq_opt->imr_interface.s_addr); + HANDLE_ERROR(error); + return error; + case IP_DROP_MEMBERSHIP: + assert(optlen == sizeof(struct ip_mreq)); + ip_mreq_opt = (struct ip_mreq *)optval; + imr_multiaddr.kind = IPv4; + ipv4_addr_to_wasi_ip4_addr(ip_mreq_opt->imr_multiaddr.s_addr, + &imr_multiaddr.addr.ip4); + error = __wasi_sock_set_ip_drop_membership( + sockfd, &imr_multiaddr, ip_mreq_opt->imr_interface.s_addr); + HANDLE_ERROR(error); + return error; + case IP_TTL: + assert(optlen == sizeof(uint8_t)); + error = __wasi_sock_set_ip_ttl(sockfd, *(uint8_t *)optval); + HANDLE_ERROR(error); + return error; + case IP_MULTICAST_TTL: + assert(optlen == sizeof(uint8_t)); + error = + __wasi_sock_set_ip_multicast_ttl(sockfd, *(uint8_t *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +set_ipproto_ipv6_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + struct ipv6_mreq *ipv6_mreq_opt; + __wasi_addr_ip_t imr_multiaddr; + + switch (optname) { + case IPV6_V6ONLY: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_ipv6_only(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case IPV6_MULTICAST_LOOP: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_ip_multicast_loop(sockfd, true, + *(bool *)optval); + HANDLE_ERROR(error); + return error; + case IPV6_JOIN_GROUP: + assert(optlen == sizeof(struct ipv6_mreq)); + ipv6_mreq_opt = (struct ipv6_mreq *)optval; + imr_multiaddr.kind = IPv6; + ipv6_addr_to_wasi_ipv6_addr( + (uint16_t *)ipv6_mreq_opt->ipv6mr_multiaddr.s6_addr, + &imr_multiaddr.addr.ip6); + error = __wasi_sock_set_ip_add_membership( + sockfd, &imr_multiaddr, ipv6_mreq_opt->ipv6mr_interface); + HANDLE_ERROR(error); + return error; + case IPV6_LEAVE_GROUP: + assert(optlen == sizeof(struct ipv6_mreq)); + ipv6_mreq_opt = (struct ipv6_mreq *)optval; + imr_multiaddr.kind = IPv6; + ipv6_addr_to_wasi_ipv6_addr( + (uint16_t *)ipv6_mreq_opt->ipv6mr_multiaddr.s6_addr, + &imr_multiaddr.addr.ip6); + error = __wasi_sock_set_ip_drop_membership( + sockfd, &imr_multiaddr, ipv6_mreq_opt->ipv6mr_interface); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + + switch (level) { + case SOL_SOCKET: + return set_sol_socket_option(sockfd, optname, optval, optlen); + case IPPROTO_TCP: + return set_ipproto_tcp_option(sockfd, optname, optval, optlen); + case IPPROTO_IP: + return set_ipproto_ip_option(sockfd, optname, optval, optlen); + case IPPROTO_IPV6: + return set_ipproto_ipv6_option(sockfd, optname, optval, optlen); + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index 7611999a..77ed30db 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -51,6 +51,8 @@ typedef struct WASIContext { struct fd_prestats *prestats; struct argv_environ_values *argv_environ; struct addr_pool *addr_pool; + char *ns_lookup_buf; + char **ns_lookup_list; char *argv_buf; char **argv_list; char *env_buf; @@ -92,6 +94,14 @@ wasi_ctx_get_addr_pool(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) return wasi_ctx->addr_pool; } +static inline char ** +wasi_ctx_get_ns_lookup_list(wasi_ctx_t wasi_ctx) +{ + if (!wasi_ctx) + return NULL; + return wasi_ctx->ns_lookup_list; +} + static wasi_errno_t wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf) { @@ -1009,8 +1019,8 @@ wasi_sock_accept(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_fd_t *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) +wasi_sock_addr_local(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); @@ -1019,14 +1029,17 @@ wasi_sock_addr_local(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *buf, if (!wasi_ctx) return __WASI_EACCES; + if (!validate_native_addr(addr, sizeof(__wasi_addr_t))) + return __WASI_EINVAL; + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - return wasi_ssp_sock_addr_local(curfds, fd, buf, buf_len); + return wasi_ssp_sock_addr_local(curfds, fd, addr); } 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) +wasi_sock_addr_remote(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); @@ -1035,16 +1048,35 @@ wasi_sock_addr_remote(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *buf, if (!wasi_ctx) return __WASI_EACCES; + if (!validate_native_addr(addr, sizeof(__wasi_addr_t))) + return __WASI_EINVAL; + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - return wasi_ssp_sock_addr_remote(curfds, fd, buf, buf_len); + return wasi_ssp_sock_addr_remote(curfds, fd, addr); } 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) +wasi_sock_addr_resolve(wasm_exec_env_t exec_env, const char *host, + const char *service, __wasi_addr_info_hints_t *hints, + __wasi_addr_info_t *addr_info, + __wasi_size_t addr_info_size, + __wasi_size_t *max_info_size) { - return __WASI_ENOSYS; + 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; + char **ns_lookup_list = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + ns_lookup_list = wasi_ctx_get_ns_lookup_list(wasi_ctx); + + return wasi_ssp_sock_addr_resolve(curfds, ns_lookup_list, host, service, + hints, addr_info, addr_info_size, + max_info_size); } static wasi_errno_t @@ -1087,30 +1119,347 @@ wasi_sock_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_addr_t *addr) return wasi_ssp_sock_connect(curfds, addr_pool, fd, addr); } +static wasi_errno_t +wasi_sock_get_broadcast(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_broadcast(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_keep_alive(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_keep_alive(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_linger(wasm_exec_env_t exec_env, wasi_fd_t fd, bool *is_enabled, + int *linger_s) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool)) + || !validate_native_addr(linger_s, sizeof(int))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_linger(curfds, fd, is_enabled, linger_s); +} + static wasi_errno_t wasi_sock_get_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, - wasi_size_t *size) + size_t *size) { - return __WASI_ENOSYS; + 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; + + if (!validate_native_addr(size, sizeof(wasi_size_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_recv_buf_size(curfds, fd, size); } static wasi_errno_t -wasi_sock_get_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse) +wasi_sock_get_recv_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t *timeout_us) { - return __WASI_ENOSYS; + 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; + + if (!validate_native_addr(timeout_us, sizeof(uint64_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_recv_timeout(curfds, fd, timeout_us); } static wasi_errno_t -wasi_sock_get_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse) +wasi_sock_get_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) { - return __WASI_ENOSYS; + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_reuse_addr(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_reuse_port(curfds, fd, is_enabled); } static wasi_errno_t wasi_sock_get_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, - wasi_size_t *size) + size_t *size) { - return __WASI_ENOSYS; + 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; + + if (!validate_native_addr(size, sizeof(__wasi_size_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_send_buf_size(curfds, fd, size); +} + +static wasi_errno_t +wasi_sock_get_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t *timeout_us) +{ + 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; + + if (!validate_native_addr(timeout_us, sizeof(uint64_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_send_timeout(curfds, fd, timeout_us); +} + +static wasi_errno_t +wasi_sock_get_tcp_fastopen_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_fastopen_connect(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_tcp_no_delay(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_no_delay(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_tcp_quick_ack(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_quick_ack(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_tcp_keep_idle(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint32_t *time_s) +{ + 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; + + if (!validate_native_addr(time_s, sizeof(uint32_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_keep_idle(curfds, fd, time_s); +} + +static wasi_errno_t +wasi_sock_get_tcp_keep_intvl(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint32_t *time_s) +{ + 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; + + if (!validate_native_addr(time_s, sizeof(uint32_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_keep_intvl(curfds, fd, time_s); +} + +static wasi_errno_t +wasi_sock_get_ip_multicast_loop(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool ipv6, bool *is_enabled) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_ip_multicast_loop(curfds, fd, ipv6, + is_enabled); +} + +static wasi_errno_t +wasi_sock_get_ip_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8_t *ttl_s) +{ + 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; + + if (!validate_native_addr(ttl_s, sizeof(uint8_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_ip_ttl(curfds, fd, ttl_s); +} + +static wasi_errno_t +wasi_sock_get_ip_multicast_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint8_t *ttl_s) +{ + 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; + + if (!validate_native_addr(ttl_s, sizeof(uint8_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_ip_multicast_ttl(curfds, fd, ttl_s); +} + +static wasi_errno_t +wasi_sock_get_ipv6_only(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + 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; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_ipv6_only(curfds, fd, is_enabled); } static wasi_errno_t @@ -1146,35 +1495,423 @@ wasi_sock_open(wasm_exec_env_t exec_env, wasi_fd_t poolfd, } static wasi_errno_t -wasi_sock_set_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, - wasi_size_t size) +wasi_sock_set_broadcast(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled) { - return __WASI_ENOSYS; + 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 wasmtime_ssp_sock_set_broadcast(curfds, fd, is_enabled); } static wasi_errno_t -wasi_sock_set_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse) +wasi_sock_set_keep_alive(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) { - return __WASI_ENOSYS; + 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 wasmtime_ssp_sock_set_keep_alive(curfds, fd, is_enabled); } static wasi_errno_t -wasi_sock_set_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse) +wasi_sock_set_linger(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled, + int linger_s) { - return __WASI_ENOSYS; + 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 wasmtime_ssp_sock_set_linger(curfds, fd, is_enabled, linger_s); } static wasi_errno_t -wasi_sock_set_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, - wasi_size_t size) +wasi_sock_set_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, size_t size) { - return __WASI_ENOSYS; + 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 wasmtime_ssp_sock_set_recv_buf_size(curfds, fd, size); } 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_data_len, - wasi_roflags_t *ro_flags) +wasi_sock_set_recv_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t timeout_us) +{ + 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 wasmtime_ssp_sock_set_recv_timeout(curfds, fd, timeout_us); +} + +static wasi_errno_t +wasi_sock_set_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + 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 wasmtime_ssp_sock_set_reuse_addr(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + 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 wasmtime_ssp_sock_set_reuse_port(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, size_t size) +{ + 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 wasmtime_ssp_sock_set_send_buf_size(curfds, fd, size); +} + +static wasi_errno_t +wasi_sock_set_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t timeout_us) +{ + 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 wasmtime_ssp_sock_set_send_timeout(curfds, fd, timeout_us); +} + +static wasi_errno_t +wasi_sock_set_tcp_fastopen_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + 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 wasmtime_ssp_sock_set_tcp_fastopen_connect(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_tcp_no_delay(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + 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 wasmtime_ssp_sock_set_tcp_no_delay(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_tcp_quick_ack(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + 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 wasmtime_ssp_sock_set_tcp_quick_ack(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_tcp_keep_idle(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint32_t time_s) +{ + 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 wasmtime_ssp_sock_set_tcp_keep_idle(curfds, fd, time_s); +} + +static wasi_errno_t +wasi_sock_set_tcp_keep_intvl(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint32_t time_s) +{ + 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 wasmtime_ssp_sock_set_tcp_keep_intvl(curfds, fd, time_s); +} + +static wasi_errno_t +wasi_sock_set_ip_multicast_loop(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool ipv6, bool is_enabled) +{ + 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 wasmtime_ssp_sock_set_ip_multicast_loop(curfds, fd, ipv6, + is_enabled); +} + +static wasi_errno_t +wasi_sock_set_ip_add_membership(wasm_exec_env_t exec_env, wasi_fd_t fd, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) +{ + 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; + + if (!validate_native_addr(imr_multiaddr, sizeof(__wasi_addr_ip_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_ip_add_membership(curfds, fd, imr_multiaddr, + imr_interface); +} + +static wasi_errno_t +wasi_sock_set_ip_drop_membership(wasm_exec_env_t exec_env, wasi_fd_t fd, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) +{ + 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; + + if (!validate_native_addr(imr_multiaddr, sizeof(__wasi_addr_ip_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_ip_drop_membership(curfds, fd, imr_multiaddr, + imr_interface); +} + +static wasi_errno_t +wasi_sock_set_ip_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8_t ttl_s) +{ + 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 wasmtime_ssp_sock_set_ip_ttl(curfds, fd, ttl_s); +} + +static wasi_errno_t +wasi_sock_set_ip_multicast_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint8_t ttl_s) +{ + 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 wasmtime_ssp_sock_set_ip_multicast_ttl(curfds, fd, ttl_s); +} + +static wasi_errno_t +wasi_sock_set_ipv6_only(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled) +{ + 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 wasmtime_ssp_sock_set_ipv6_only(curfds, fd, is_enabled); +} + +static wasi_errno_t +allocate_iovec_app_buffer(wasm_module_inst_t module_inst, + const iovec_app_t *data, uint32 data_len, + uint8 **buf_ptr, uint64 *buf_len) +{ + uint64 total_size = 0; + uint32 i; + uint8 *buf_begin = NULL; + + if (data_len == 0) { + return __WASI_EINVAL; + } + + total_size = sizeof(iovec_app_t) * (uint64)data_len; + if (total_size >= UINT32_MAX + || !validate_native_addr((void *)data, (uint32)total_size)) + return __WASI_EINVAL; + + for (total_size = 0, i = 0; i < data_len; i++, data++) { + total_size += data->buf_len; + } + + if (total_size == 0) { + return __WASI_EINVAL; + } + + if (total_size >= UINT32_MAX + || !(buf_begin = wasm_runtime_malloc((uint32)total_size))) { + return __WASI_ENOMEM; + } + + *buf_len = total_size; + *buf_ptr = buf_begin; + + return __WASI_ESUCCESS; +} + +static inline size_t +min(size_t a, size_t b) +{ + return a > b ? b : a; +} + +static wasi_errno_t +copy_buffer_to_iovec_app(wasm_module_inst_t module_inst, uint8 *buf_begin, + uint32 buf_size, iovec_app_t *data, uint32 data_len, + uint32 size_to_copy) +{ + uint8 *buf = buf_begin; + uint32 i; + uint32 size_to_copy_into_iovec; + + if (buf_size < size_to_copy) { + return __WASI_EINVAL; + } + + for (i = 0; i < data_len; data++, i++) { + char *native_addr; + + if (!validate_app_addr(data->buf_offset, data->buf_len)) { + return __WASI_EINVAL; + } + + if (buf >= buf_begin + buf_size + || buf + data->buf_len < buf /* integer overflow */ + || buf + data->buf_len > buf_begin + buf_size + || size_to_copy == 0) { + break; + } + + /** + * If our app buffer size is smaller than the amount to be copied, + * only copy the amount in the app buffer. Otherwise, we fill the iovec + * buffer and reduce size to copy on the next iteration + */ + size_to_copy_into_iovec = min(data->buf_len, size_to_copy); + + native_addr = (void *)addr_app_to_native(data->buf_offset); + bh_memcpy_s(native_addr, size_to_copy_into_iovec, buf, + size_to_copy_into_iovec); + buf += size_to_copy_into_iovec; + size_to_copy -= size_to_copy_into_iovec; + } + + return __WASI_ESUCCESS; +} + +static wasi_errno_t +wasi_sock_recv_from(wasm_exec_env_t exec_env, wasi_fd_t sock, + iovec_app_t *ri_data, uint32 ri_data_len, + wasi_riflags_t ri_flags, __wasi_addr_t *src_addr, + uint32 *ro_data_len) { /** * ri_data_len is the length of a list of iovec_app_t, which head is @@ -1184,9 +1921,6 @@ wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); uint64 total_size; - uint32 i; - iovec_app_t *ri_data_orig = ri_data; - uint8 *buf = NULL; uint8 *buf_begin = NULL; wasi_errno_t err; size_t recv_bytes = 0; @@ -1195,55 +1929,28 @@ wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, return __WASI_EINVAL; } - if (ri_data_len == 0) { - return __WASI_EINVAL; - } - - total_size = sizeof(iovec_app_t) * (uint64)ri_data_len; - 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)) + if (!validate_native_addr(ro_data_len, (uint32)sizeof(uint32))) return __WASI_EINVAL; - /* receive and scatter*/ - for (total_size = 0, i = 0; i < ri_data_len; i++, ri_data++) { - total_size += ri_data->buf_len; - } - if (total_size >= UINT32_MAX - || !(buf_begin = wasm_runtime_malloc((uint32)total_size))) { - return __WASI_ENOMEM; + err = allocate_iovec_app_buffer(module_inst, ri_data, ri_data_len, + &buf_begin, &total_size); + if (err != __WASI_ESUCCESS) { + goto fail; } + memset(buf_begin, 0, total_size); *ro_data_len = 0; - err = wasmtime_ssp_sock_recv(curfds, sock, buf_begin, total_size, - &recv_bytes); + err = wasmtime_ssp_sock_recv_from(curfds, sock, buf_begin, total_size, + ri_flags, src_addr, &recv_bytes); if (err != __WASI_ESUCCESS) { goto fail; } *ro_data_len = (uint32)recv_bytes; - buf = buf_begin; - ri_data = ri_data_orig; - for (i = 0; i < ri_data_len; ri_data++, i++) { - char *native_addr; + err = copy_buffer_to_iovec_app(module_inst, buf_begin, (uint32)total_size, + ri_data, ri_data_len, (uint32)recv_bytes); - if ((uint32)(buf - buf_begin) >= *ro_data_len) { - break; - } - - if (!validate_app_addr(ri_data->buf_offset, ri_data->buf_len)) { - err = __WASI_EINVAL; - goto fail; - } - - native_addr = (void *)addr_app_to_native(ri_data->buf_offset); - bh_memcpy_s(native_addr, ri_data->buf_len, buf, ri_data->buf_len); - buf += ri_data->buf_len; - } - - *ro_flags = ri_flags; fail: if (buf_begin) { wasm_runtime_free(buf_begin); @@ -1251,6 +1958,59 @@ fail: return err; } +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_data_len, + wasi_roflags_t *ro_flags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + __wasi_addr_t src_addr; + wasi_errno_t error; + + if (!validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t))) + return __WASI_EINVAL; + + error = wasi_sock_recv_from(exec_env, sock, ri_data, ri_data_len, ri_flags, + &src_addr, ro_data_len); + *ro_flags = ri_flags; + + return error; +} + +static wasi_errno_t +convert_iovec_app_to_buffer(wasm_module_inst_t module_inst, + const iovec_app_t *si_data, uint32 si_data_len, + uint8 **buf_ptr, uint64 *buf_len) +{ + uint32 i; + const iovec_app_t *si_data_orig = si_data; + uint8 *buf = NULL; + wasi_errno_t error; + + error = allocate_iovec_app_buffer(module_inst, si_data, si_data_len, + buf_ptr, buf_len); + if (error != __WASI_ESUCCESS) { + return error; + } + + buf = *buf_ptr; + si_data = si_data_orig; + for (i = 0; i < si_data_len; i++, si_data++) { + char *native_addr; + + if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) { + wasm_runtime_free(*buf_ptr); + return __WASI_EINVAL; + } + + native_addr = (char *)addr_app_to_native(si_data->buf_offset); + bh_memcpy_s(buf, si_data->buf_len, native_addr, si_data->buf_len); + buf += si_data->buf_len; + } + + 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, @@ -1263,11 +2023,8 @@ wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock, 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); - uint64 total_size = 0; - uint32 i; - const iovec_app_t *si_data_orig = si_data; + uint64 buf_size = 0; uint8 *buf = NULL; - uint8 *buf_begin = NULL; wasi_errno_t err; size_t send_bytes = 0; @@ -1275,49 +2032,61 @@ wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock, return __WASI_EINVAL; } - if (si_data_len == 0) { - return __WASI_EINVAL; - } - - total_size = sizeof(iovec_app_t) * (uint64)si_data_len; - if (!validate_native_addr(so_data_len, sizeof(uint32)) - || total_size >= UINT32_MAX - || !validate_native_addr((void *)si_data, (uint32)total_size)) + if (!validate_native_addr(so_data_len, sizeof(uint32))) return __WASI_EINVAL; - /* gather and send */ - for (total_size = 0, i = 0; i < si_data_len; i++, si_data++) { - total_size += si_data->buf_len; - } - if (total_size >= UINT32_MAX - || !(buf_begin = wasm_runtime_malloc((uint32)total_size))) { - return __WASI_ENOMEM; - } - - buf = buf_begin; - si_data = si_data_orig; - for (i = 0; i < si_data_len; i++, si_data++) { - char *native_addr; - - if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) { - err = __WASI_EINVAL; - goto fail; - } - - native_addr = (char *)addr_app_to_native(si_data->buf_offset); - bh_memcpy_s(buf, si_data->buf_len, native_addr, si_data->buf_len); - buf += si_data->buf_len; - } + err = convert_iovec_app_to_buffer(module_inst, si_data, si_data_len, &buf, + &buf_size); + if (err != __WASI_ESUCCESS) + return err; *so_data_len = 0; - err = wasmtime_ssp_sock_send(curfds, sock, buf_begin, total_size, - &send_bytes); + err = wasmtime_ssp_sock_send(curfds, sock, buf, buf_size, &send_bytes); *so_data_len = (uint32)send_bytes; -fail: - if (buf_begin) { - wasm_runtime_free(buf_begin); + wasm_runtime_free(buf); + + return err; +} + +static wasi_errno_t +wasi_sock_send_to(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, const __wasi_addr_t *dest_addr, + 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); + uint64 buf_size = 0; + uint8 *buf = NULL; + wasi_errno_t err; + size_t send_bytes = 0; + struct addr_pool *addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx); + + if (!wasi_ctx) { + return __WASI_EINVAL; } + + if (!validate_native_addr(so_data_len, sizeof(uint32))) + return __WASI_EINVAL; + + err = convert_iovec_app_to_buffer(module_inst, si_data, si_data_len, &buf, + &buf_size); + if (err != __WASI_ESUCCESS) + return err; + + *so_data_len = 0; + err = wasmtime_ssp_sock_send_to(curfds, addr_pool, sock, buf, buf_size, + si_flags, dest_addr, &send_bytes); + *so_data_len = (uint32)send_bytes; + + wasm_runtime_free(buf); + return err; } @@ -1388,24 +2157,56 @@ static NativeSymbol native_symbols_libc_wasi[] = { 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_addr_local, "(i*)i"), + REG_NATIVE_FUNC(sock_addr_remote, "(i*)i"), + REG_NATIVE_FUNC(sock_addr_resolve, "($$**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_broadcast, "(i*)i"), + REG_NATIVE_FUNC(sock_get_keep_alive, "(i*)i"), + REG_NATIVE_FUNC(sock_get_linger, "(i**)i"), REG_NATIVE_FUNC(sock_get_recv_buf_size, "(i*)i"), + REG_NATIVE_FUNC(sock_get_recv_timeout, "(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_get_send_timeout, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_fastopen_connect, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_keep_idle, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_keep_intvl, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_no_delay, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_quick_ack, "(i*)i"), + REG_NATIVE_FUNC(sock_get_ip_multicast_loop, "(ii*)i"), + REG_NATIVE_FUNC(sock_get_ip_multicast_ttl, "(i*)i"), + REG_NATIVE_FUNC(sock_get_ip_ttl, "(i*)i"), + REG_NATIVE_FUNC(sock_get_ipv6_only, "(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_recv_from, "(i*ii**)i"), REG_NATIVE_FUNC(sock_send, "(i*ii*)i"), + REG_NATIVE_FUNC(sock_send_to, "(i*ii**)i"), + REG_NATIVE_FUNC(sock_set_broadcast, "(ii)i"), + REG_NATIVE_FUNC(sock_set_keep_alive, "(ii)i"), + REG_NATIVE_FUNC(sock_set_linger, "(iii)i"), REG_NATIVE_FUNC(sock_set_recv_buf_size, "(ii)i"), + REG_NATIVE_FUNC(sock_set_recv_timeout, "(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_set_send_timeout, "(iI)i"), + REG_NATIVE_FUNC(sock_set_tcp_fastopen_connect, "(ii)i"), + REG_NATIVE_FUNC(sock_set_tcp_keep_idle, "(ii)i"), + REG_NATIVE_FUNC(sock_set_tcp_keep_intvl, "(ii)i"), + REG_NATIVE_FUNC(sock_set_tcp_no_delay, "(ii)i"), + REG_NATIVE_FUNC(sock_set_tcp_quick_ack, "(ii)i"), + REG_NATIVE_FUNC(sock_set_ip_multicast_loop, "(iii)i"), + REG_NATIVE_FUNC(sock_set_ip_multicast_ttl, "(ii)i"), + REG_NATIVE_FUNC(sock_set_ip_add_membership, "(i*i)i"), + REG_NATIVE_FUNC(sock_set_ip_drop_membership, "(i*i)i"), + REG_NATIVE_FUNC(sock_set_ip_ttl, "(ii)i"), + REG_NATIVE_FUNC(sock_set_ipv6_only, "(ii)i"), REG_NATIVE_FUNC(sock_shutdown, "(ii)i"), REG_NATIVE_FUNC(sched_yield, "()i"), }; 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 8c9d265a..60e1975d 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 @@ -18,6 +18,7 @@ #ifndef WASMTIME_SSP_H #define WASMTIME_SSP_H +#include #include #include @@ -588,6 +589,14 @@ typedef struct __wasi_addr_ip6_port_t { __wasi_ip_port_t port; } __wasi_addr_ip6_port_t; +typedef struct __wasi_addr_ip_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_t ip4; + __wasi_addr_ip6_t ip6; + } addr; +} __wasi_addr_ip_t; + typedef struct __wasi_addr_t { __wasi_addr_type_t kind; union { @@ -598,6 +607,18 @@ typedef struct __wasi_addr_t { typedef enum { INET4 = 0, INET6 } __wasi_address_family_t; +typedef struct __wasi_addr_info_t { + __wasi_addr_t addr; + __wasi_sock_type_t type; +} __wasi_addr_info_t; + +typedef struct __wasi_addr_info_hints_t { + __wasi_sock_type_t type; + __wasi_address_family_t family; + // this is to workaround lack of optional parameters + uint8_t hints_enabled; +} __wasi_addr_info_hints_t; + #if defined(WASMTIME_SSP_WASI_API) #define WASMTIME_SSP_SYSCALL_NAME(name) \ asm("__wasi_" #name) @@ -995,7 +1016,7 @@ 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 + __wasi_fd_t fd, __wasi_addr_t *addr ) __attribute__((__warn_unused_result__)); __wasi_errno_t @@ -1003,7 +1024,7 @@ 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 + __wasi_fd_t fd, __wasi_addr_t *addr ) __attribute__((__warn_unused_result__)); __wasi_errno_t @@ -1023,6 +1044,16 @@ wasi_ssp_sock_bind( __wasi_fd_t fd, __wasi_addr_t *addr ) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_addr_resolve( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, char **ns_lookup_list, +#endif + const char *host, const char* service, + __wasi_addr_info_hints_t *hints, __wasi_addr_info_t *addr_info, + __wasi_size_t addr_info_size, __wasi_size_t *max_info_size +) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasi_ssp_sock_connect( #if !defined(WASMTIME_SSP_STATIC_CURFDS) @@ -1049,6 +1080,18 @@ __wasi_errno_t wasmtime_ssp_sock_recv( size_t *recv_len ) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__)); +__wasi_errno_t wasmtime_ssp_sock_recv_from( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + void *buf, + size_t buf_len, + __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, + size_t *recv_len +) WASMTIME_SSP_SYSCALL_NAME(sock_recv_from) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasmtime_ssp_sock_send( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, @@ -1059,6 +1102,18 @@ __wasi_errno_t wasmtime_ssp_sock_send( size_t *sent_len ) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__)); +__wasi_errno_t wasmtime_ssp_sock_send_to( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t sock, + const void *buf, + size_t buf_len, + __wasi_siflags_t si_flags, + const __wasi_addr_t *dest_addr, + size_t *sent_len +) WASMTIME_SSP_SYSCALL_NAME(sock_send_to) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasmtime_ssp_sock_shutdown( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, @@ -1066,6 +1121,315 @@ __wasi_errno_t wasmtime_ssp_sock_shutdown( __wasi_fd_t sock ) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__)); +__wasi_errno_t wasmtime_ssp_sock_set_recv_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_recv_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t *timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_send_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_send_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t *timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + size_t bufsiz +) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_buf_size) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + size_t *bufsiz +) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_buf_size) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + size_t bufsiz +) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_buf_size) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + size_t *bufsiz +) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_buf_size) __attribute__((__warn_unused_result__)); + + +__wasi_errno_t wasmtime_ssp_sock_set_keep_alive( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_keep_alive) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_keep_alive( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_addr) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_port) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_linger( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled, + int linger_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_linger( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool *is_enabled, int *linger_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_linger) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_broadcast( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_broadcast) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_broadcast( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_no_delay( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_no_delay) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_no_delay( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_quick_ack( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_quick_ack) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_quick_ack( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_idle( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint32_t time_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_idle) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_idle( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint32_t *time_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_idle) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_intvl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint32_t time_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_intvl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_intvl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint32_t *time_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_intvl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_fastopen_connect( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_fastopen_connect( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_loop( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool ipv6, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_loop) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_loop( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool ipv6, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_add_membership( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_add_membership) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_drop_membership( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_drop_membership) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_ttl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint8_t ttl_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_ttl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_ip_ttl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint8_t *ttl_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_ttl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_ttl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint8_t ttl_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_ttl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_ttl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint8_t *ttl_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_ttl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ipv6_only( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ipv6_only) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_ipv6_only( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasmtime_ssp_sched_yield(void) WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__)); 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 cc618680..b0760fd8 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 @@ -161,6 +161,31 @@ convert_errno(int error) return errors[error]; } +static bool +ns_lookup_list_search(char **list, const char *host) +{ + size_t host_len = strlen(host), suffix_len; + + while (*list) { + if (*list[0] == '*') { + suffix_len = strlen(*list) - 1; + if (suffix_len <= host_len + && strncmp(host + host_len - suffix_len, *list + 1, suffix_len) + == 0) { + return true; + } + } + else { + if (strcmp(*list, host) == 0) { + return true; + } + } + list++; + } + + return false; +} + // Converts a POSIX timespec to a CloudABI timestamp. static __wasi_timestamp_t convert_timespec(const struct timespec *ts) @@ -199,6 +224,82 @@ convert_clockid(__wasi_clockid_t in, clockid_t *out) } } +static void +wasi_addr_to_bh_sockaddr(const __wasi_addr_t *wasi_addr, + bh_sockaddr_t *sockaddr) +{ + if (wasi_addr->kind == IPv4) { + sockaddr->addr_bufer.ipv4 = (wasi_addr->addr.ip4.addr.n0 << 24) + | (wasi_addr->addr.ip4.addr.n1 << 16) + | (wasi_addr->addr.ip4.addr.n2 << 8) + | wasi_addr->addr.ip4.addr.n3; + sockaddr->is_ipv4 = true; + sockaddr->port = wasi_addr->addr.ip4.port; + } + else { + sockaddr->addr_bufer.ipv6[0] = wasi_addr->addr.ip6.addr.n0; + sockaddr->addr_bufer.ipv6[1] = wasi_addr->addr.ip6.addr.n1; + sockaddr->addr_bufer.ipv6[2] = wasi_addr->addr.ip6.addr.n2; + sockaddr->addr_bufer.ipv6[3] = wasi_addr->addr.ip6.addr.n3; + sockaddr->addr_bufer.ipv6[4] = wasi_addr->addr.ip6.addr.h0; + sockaddr->addr_bufer.ipv6[5] = wasi_addr->addr.ip6.addr.h1; + sockaddr->addr_bufer.ipv6[6] = wasi_addr->addr.ip6.addr.h2; + sockaddr->addr_bufer.ipv6[7] = wasi_addr->addr.ip6.addr.h3; + sockaddr->is_ipv4 = false; + sockaddr->port = wasi_addr->addr.ip6.port; + } +} + +// Converts an IPv6 binary address object to WASI address object. +static void +bh_sockaddr_to_wasi_addr(const bh_sockaddr_t *sockaddr, + __wasi_addr_t *wasi_addr) +{ + if (sockaddr->is_ipv4) { + wasi_addr->kind = IPv4; + wasi_addr->addr.ip4.port = sockaddr->port; + wasi_addr->addr.ip4.addr.n0 = + (sockaddr->addr_bufer.ipv4 & 0xFF000000) >> 24; + wasi_addr->addr.ip4.addr.n1 = + (sockaddr->addr_bufer.ipv4 & 0x00FF0000) >> 16; + wasi_addr->addr.ip4.addr.n2 = + (sockaddr->addr_bufer.ipv4 & 0x0000FF00) >> 8; + wasi_addr->addr.ip4.addr.n3 = (sockaddr->addr_bufer.ipv4 & 0x000000FF); + } + else { + wasi_addr->kind = IPv6; + wasi_addr->addr.ip6.port = sockaddr->port; + wasi_addr->addr.ip6.addr.n0 = sockaddr->addr_bufer.ipv6[0]; + wasi_addr->addr.ip6.addr.n1 = sockaddr->addr_bufer.ipv6[1]; + wasi_addr->addr.ip6.addr.n2 = sockaddr->addr_bufer.ipv6[2]; + wasi_addr->addr.ip6.addr.n3 = sockaddr->addr_bufer.ipv6[3]; + wasi_addr->addr.ip6.addr.h0 = sockaddr->addr_bufer.ipv6[4]; + wasi_addr->addr.ip6.addr.h1 = sockaddr->addr_bufer.ipv6[5]; + wasi_addr->addr.ip6.addr.h2 = sockaddr->addr_bufer.ipv6[6]; + wasi_addr->addr.ip6.addr.h3 = sockaddr->addr_bufer.ipv6[7]; + } +} + +static void +wasi_addr_ip_to_bh_ip_addr_buffer(__wasi_addr_ip_t *addr, + bh_ip_addr_buffer_t *out) +{ + if (addr->kind == IPv4) { + out->ipv4 = htonl((addr->addr.ip4.n0 << 24) | (addr->addr.ip4.n1 << 16) + | (addr->addr.ip4.n2 << 8) | addr->addr.ip4.n3); + } + else { + out->ipv6[0] = htons(addr->addr.ip6.n0); + out->ipv6[1] = htons(addr->addr.ip6.n1); + out->ipv6[2] = htons(addr->addr.ip6.n2); + out->ipv6[3] = htons(addr->addr.ip6.n3); + out->ipv6[4] = htons(addr->addr.ip6.h0); + out->ipv6[5] = htons(addr->addr.ip6.h1); + out->ipv6[6] = htons(addr->addr.ip6.h2); + out->ipv6[7] = htons(addr->addr.ip6.h3); + } +} + __wasi_errno_t wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution) @@ -2852,16 +2953,26 @@ wasi_ssp_sock_addr_local( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len) + __wasi_fd_t fd, __wasi_addr_t *addr) { struct fd_object *fo; + bh_sockaddr_t bh_addr; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0); if (error != __WASI_ESUCCESS) return error; + ret = os_socket_addr_local(fd_number(fo), &bh_addr); fd_object_release(fo); - return __WASI_ENOSYS; + if (ret != BHT_OK) { + return convert_errno(errno); + } + + bh_sockaddr_to_wasi_addr(&bh_addr, addr); + + return __WASI_ESUCCESS; } __wasi_errno_t @@ -2869,16 +2980,55 @@ 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) + __wasi_fd_t fd, __wasi_addr_t *addr) { struct fd_object *fo; + bh_sockaddr_t bh_addr; + int ret; + __wasi_errno_t error = - fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_REMOTE, 0); + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0); if (error != __WASI_ESUCCESS) return error; + ret = os_socket_addr_remote(fd_number(fo), &bh_addr); fd_object_release(fo); - return __WASI_ENOSYS; + if (ret != BHT_OK) { + return convert_errno(errno); + } + + bh_sockaddr_to_wasi_addr(&bh_addr, addr); + + return __WASI_ESUCCESS; +} + +static bool +wasi_addr_to_string(const __wasi_addr_t *addr, char *buf, size_t buflen) +{ + if (addr->kind == IPv4) { + const char *format = "%u.%u.%u.%u"; + + assert(buflen >= 16); + + snprintf(buf, buflen, format, addr->addr.ip4.addr.n0, + addr->addr.ip4.addr.n1, addr->addr.ip4.addr.n2, + addr->addr.ip4.addr.n3); + + return true; + } + else if (addr->kind == IPv6) { + const char *format = "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"; + __wasi_addr_ip6_t ipv6 = addr->addr.ip6.addr; + + assert(buflen >= 40); + + snprintf(buf, buflen, format, ipv6.n0, ipv6.n1, ipv6.n2, ipv6.n3, + ipv6.h0, ipv6.h1, ipv6.h2, ipv6.h3); + + return true; + } + + return false; } __wasi_errno_t @@ -2888,15 +3038,15 @@ wasi_ssp_sock_bind( #endif __wasi_fd_t fd, __wasi_addr_t *addr) { - char buf[24] = { 0 }; - const char *format = "%u.%u.%u.%u"; + char buf[48] = { 0 }; struct fd_object *fo; __wasi_errno_t error; - int port = addr->addr.ip4.port; + int port = addr->kind == IPv4 ? addr->addr.ip4.port : addr->addr.ip6.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 (!wasi_addr_to_string(addr, buf, sizeof(buf))) { + return __WASI_EPROTONOSUPPORT; + } if (!addr_pool_search(addr_pool, buf)) { return __WASI_EACCES; @@ -2915,6 +3065,55 @@ wasi_ssp_sock_bind( return __WASI_ESUCCESS; } +__wasi_errno_t +wasi_ssp_sock_addr_resolve( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, char **ns_lookup_list, +#endif + const char *host, const char *service, __wasi_addr_info_hints_t *hints, + __wasi_addr_info_t *addr_info, __wasi_size_t addr_info_size, + __wasi_size_t *max_info_size) +{ + bh_addr_info_t *wamr_addr_info = + wasm_runtime_malloc(addr_info_size * sizeof(bh_addr_info_t)); + uint8_t hints_is_ipv4 = hints->family == INET4; + uint8_t hints_is_tcp = hints->type == SOCKET_STREAM; + size_t _max_info_size; + size_t actual_info_size; + + if (!ns_lookup_list_search(ns_lookup_list, host)) { + return __WASI_EACCES; + } + + if (!wamr_addr_info) { + return __WASI_ENOMEM; + } + + int ret = os_socket_addr_resolve( + host, service, hints->hints_enabled ? &hints_is_tcp : NULL, + hints->hints_enabled ? &hints_is_ipv4 : NULL, wamr_addr_info, + addr_info_size, &_max_info_size); + + if (ret != BHT_OK) { + wasm_runtime_free(wamr_addr_info); + return convert_errno(errno); + } + + *max_info_size = _max_info_size; + actual_info_size = + addr_info_size < *max_info_size ? addr_info_size : *max_info_size; + + for (size_t i = 0; i < actual_info_size; i++) { + addr_info[i].type = + wamr_addr_info[i].is_tcp ? SOCKET_STREAM : SOCKET_DGRAM; + bh_sockaddr_to_wasi_addr(&wamr_addr_info[i].sockaddr, + &addr_info[i].addr); + } + + wasm_runtime_free(wamr_addr_info); + return __WASI_ESUCCESS; +} + __wasi_errno_t wasi_ssp_sock_connect( #if !defined(WASMTIME_SSP_STATIC_CURFDS) @@ -2922,14 +3121,14 @@ wasi_ssp_sock_connect( #endif __wasi_fd_t fd, __wasi_addr_t *addr) { - char buf[24] = { 0 }; - const char *format = "%u.%u.%u.%u"; + char buf[48] = { 0 }; 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); + if (!wasi_addr_to_string(addr, buf, sizeof(buf))) { + return __WASI_EPROTONOSUPPORT; + } if (!addr_pool_search(addr_pool, buf)) { return __WASI_EACCES; @@ -2939,7 +3138,9 @@ wasi_ssp_sock_connect( if (error != __WASI_ESUCCESS) return error; - ret = os_socket_connect(fd_number(fo), buf, addr->addr.ip4.port); + ret = os_socket_connect(fd_number(fo), buf, + addr->kind == IPv4 ? addr->addr.ip4.port + : addr->addr.ip6.port); fd_object_release(fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -2980,7 +3181,8 @@ wasi_ssp_sock_open( __wasi_fd_t *sockfd) { bh_socket_t sock; - int tcp_or_udp = 0; + bool is_tcp = SOCKET_DGRAM == socktype ? false : true; + bool is_ipv4 = INET6 == af ? false : true; int ret; __wasi_filetype_t wasi_type; __wasi_rights_t max_base, max_inheriting; @@ -2988,13 +3190,7 @@ wasi_ssp_sock_open( (void)poolfd; - if (INET4 != af) { - return __WASI_EAFNOSUPPORT; - } - - tcp_or_udp = SOCKET_DGRAM == socktype ? 0 : 1; - - ret = os_socket_create(&sock, tcp_or_udp); + ret = os_socket_create(&sock, is_ipv4, is_tcp); if (BHT_OK != ret) { return convert_errno(errno); } @@ -3029,9 +3225,24 @@ wasmtime_ssp_sock_recv( struct fd_table *curfds, #endif __wasi_fd_t sock, void *buf, size_t buf_len, size_t *recv_len) +{ + __wasi_addr_t src_addr; + + return wasmtime_ssp_sock_recv_from(curfds, sock, buf, buf_len, 0, &src_addr, + recv_len); +} + +__wasi_errno_t +wasmtime_ssp_sock_recv_from( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, void *buf, size_t buf_len, __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, size_t *recv_len) { struct fd_object *fo; __wasi_errno_t error; + bh_sockaddr_t sockaddr; int ret; error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0); @@ -3039,12 +3250,14 @@ wasmtime_ssp_sock_recv( return error; } - ret = os_socket_recv(fd_number(fo), buf, buf_len); + ret = os_socket_recv_from(fd_number(fo), buf, buf_len, 0, &sockaddr); fd_object_release(fo); if (-1 == ret) { return convert_errno(errno); } + bh_sockaddr_to_wasi_addr(&sockaddr, src_addr); + *recv_len = (size_t)ret; return __WASI_ESUCCESS; } @@ -3075,6 +3288,45 @@ wasmtime_ssp_sock_send( return __WASI_ESUCCESS; } +__wasi_errno_t +wasmtime_ssp_sock_send_to( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t sock, const void *buf, size_t buf_len, + __wasi_siflags_t si_flags, const __wasi_addr_t *dest_addr, size_t *sent_len) +{ + char addr_buf[48] = { 0 }; + struct fd_object *fo; + __wasi_errno_t error; + int ret; + bh_sockaddr_t sockaddr; + + if (!wasi_addr_to_string(dest_addr, addr_buf, sizeof(addr_buf))) { + return __WASI_EPROTONOSUPPORT; + } + + if (!addr_pool_search(addr_pool, addr_buf)) { + return __WASI_EACCES; + } + + error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) { + return error; + } + + wasi_addr_to_bh_sockaddr(dest_addr, &sockaddr); + + ret = os_socket_send_to(fd_number(fo), buf, buf_len, 0, &sockaddr); + fd_object_release(fo); + if (-1 == ret) { + 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) @@ -3220,9 +3472,8 @@ fd_prestats_destroy(struct fd_prestats *pt) bool addr_pool_init(struct addr_pool *addr_pool) { - addr_pool->next = NULL; - addr_pool->addr = 0; - addr_pool->mask = 0; + memset(addr_pool, 0, sizeof(*addr_pool)); + return true; } @@ -3231,6 +3482,7 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask) { struct addr_pool *cur = addr_pool; struct addr_pool *next; + bh_ip_addr_buffer_t target; if (!addr_pool) { return false; @@ -3242,9 +3494,20 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask) next->next = NULL; next->mask = mask; - if (os_socket_inet_network(addr, &next->addr) != BHT_OK) { - wasm_runtime_free(next); - return false; + + if (os_socket_inet_network(true, addr, &target) != BHT_OK) { + // If parsing IPv4 fails, try IPv6 + if (os_socket_inet_network(false, addr, &target) != BHT_OK) { + wasm_runtime_free(next); + return false; + } + next->type = IPv6; + bh_memcpy_s(next->addr.ip6, sizeof(next->addr.ip6), target.ipv6, + sizeof(target.ipv6)); + } + else { + next->type = IPv4; + next->addr.ip4 = target.ipv4; } /* attach with */ @@ -3255,47 +3518,106 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask) return true; } -static bool -compare_address(const struct addr_pool *addr_pool_entry, const char *addr) +static inline size_t +min(size_t a, size_t b) { - /* host order */ - uint32 target; - uint32 address = addr_pool_entry->addr; - /* 0.0.0.0 means any address */ - if (0 == address) { + return a > b ? b : a; +} + +static void +init_address_mask(uint8_t *buf, size_t buflen, size_t mask) +{ + size_t element_size = sizeof(uint8_t) * 8; + + for (size_t i = 0; i < buflen; i++) { + if (mask <= i * element_size) { + buf[i] = 0; + } + else { + size_t offset = min(mask - i * element_size, element_size); + buf[i] = (~0u) << (element_size - offset); + } + } +} + +/* target must be in network byte order */ +static bool +compare_address(const struct addr_pool *addr_pool_entry, + bh_ip_addr_buffer_t *target) +{ + uint8_t maskbuf[16] = { 0 }; + uint8_t basebuf[16] = { 0 }; + size_t addr_size; + uint8_t max_addr_mask; + + if (addr_pool_entry->type == IPv4) { + uint32_t addr_ip4 = htonl(addr_pool_entry->addr.ip4); + bh_memcpy_s(basebuf, sizeof(addr_ip4), &addr_ip4, sizeof(addr_ip4)); + addr_size = 4; + } + else { + uint16_t partial_addr_ip6; + for (int i = 0; i < 8; i++) { + partial_addr_ip6 = htons(addr_pool_entry->addr.ip6[i]); + bh_memcpy_s(&basebuf[i * sizeof(partial_addr_ip6)], + sizeof(partial_addr_ip6), &partial_addr_ip6, + sizeof(partial_addr_ip6)); + } + addr_size = 16; + } + max_addr_mask = addr_size * 8; + + /* IPv4 0.0.0.0 or IPv6 :: means any address */ + if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) { return true; } - if (os_socket_inet_network(addr, &target) != BHT_OK) { + /* No support for invalid mask value */ + if (addr_pool_entry->mask > max_addr_mask) { return false; } - const uint32 max_mask_value = 32; - /* no support for invalid mask values */ - if (addr_pool_entry->mask > max_mask_value) { - return false; + init_address_mask(maskbuf, addr_size, addr_pool_entry->mask); + + for (size_t i = 0; i < addr_size; i++) { + uint8_t addr_mask = target->data[i] & maskbuf[i]; + uint8_t range_mask = basebuf[i] & maskbuf[i]; + if (addr_mask != range_mask) { + return false; + } } - /* convert mask number into 32-bit mask value, i.e. mask /24 will be - converted to 4294967040 (binary: 11111111 11111111 11111111 00000000) */ - uint32 mask = 0; - for (int i = 0; i < addr_pool_entry->mask; i++) { - mask |= 1 << (max_mask_value - 1 - i); - } - - uint32 first_address = address & mask; - uint32 last_address = address | (~mask); - return first_address <= target && target <= last_address; + return true; } bool addr_pool_search(struct addr_pool *addr_pool, const char *addr) { struct addr_pool *cur = addr_pool->next; + bh_ip_addr_buffer_t target; + __wasi_addr_type_t addr_type; + + if (os_socket_inet_network(true, addr, &target) != BHT_OK) { + size_t i; + + if (os_socket_inet_network(false, addr, &target) != BHT_OK) { + return false; + } + addr_type = IPv6; + for (i = 0; i < sizeof(target.ipv6) / sizeof(target.ipv6[0]); i++) { + target.ipv6[i] = htons(target.ipv6[i]); + } + } + else { + addr_type = IPv4; + target.ipv4 = htonl(target.ipv4); + } while (cur) { - if (compare_address(cur, addr)) + if (cur->type == addr_type && compare_address(cur, &target)) { return true; + } + cur = cur->next; } @@ -3313,3 +3635,203 @@ addr_pool_destroy(struct addr_pool *addr_pool) cur = next; } } + +#ifndef WASMTIME_SSP_STATIC_CURFDS +#define WASMTIME_SSP_PASSTHROUGH_FD_TABLE struct fd_table *curfds, +#else +#define WASMTIME_SSP_PASSTHROUGH_FD_TABLE +#endif + +// Defines a function that passes through the socket option to the OS +// implementation +#define WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(FUNC_NAME, OPTION_TYPE) \ + __wasi_errno_t wasmtime_ssp_sock_##FUNC_NAME( \ + WASMTIME_SSP_PASSTHROUGH_FD_TABLE __wasi_fd_t sock, \ + OPTION_TYPE option) \ + { \ + struct fd_object *fo; \ + __wasi_errno_t error; \ + int ret; \ + error = fd_object_get(curfds, &fo, sock, 0, 0); \ + if (error != 0) \ + return error; \ + ret = os_socket_##FUNC_NAME(fd_number(fo), option); \ + fd_object_release(fo); \ + if (BHT_OK != ret) \ + return convert_errno(errno); \ + return __WASI_ESUCCESS; \ + } + +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_timeout, uint64) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_timeout, uint64 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_timeout, uint64) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_timeout, uint64 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_buf_size, size_t) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_buf_size, size_t *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_buf_size, size_t) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_buf_size, size_t *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_broadcast, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_broadcast, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_keep_alive, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_keep_alive, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_reuse_addr, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_reuse_addr, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_reuse_port, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_reuse_port, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_no_delay, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_no_delay, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_quick_ack, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_quick_ack, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_keep_idle, uint32) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_keep_idle, uint32 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_keep_intvl, uint32) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_keep_intvl, uint32 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_fastopen_connect, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_fastopen_connect, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ip_ttl, uint8_t) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ip_ttl, uint8_t *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ip_multicast_ttl, uint8_t) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ip_multicast_ttl, uint8_t *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ipv6_only, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ipv6_only, bool *) + +#undef WASMTIME_SSP_PASSTHROUGH_FD_TABLE +#undef WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION + +__wasi_errno_t +wasmtime_ssp_sock_set_linger( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool is_enabled, int linger_s) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_set_linger(fd_number(fo), is_enabled, linger_s); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_get_linger( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool *is_enabled, int *linger_s) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_get_linger(fd_number(fo), is_enabled, linger_s); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_add_membership( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, __wasi_addr_ip_t *imr_multiaddr, uint32_t imr_interface) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + bh_ip_addr_buffer_t addr_info; + bool is_ipv6; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info); + is_ipv6 = imr_multiaddr->kind == IPv6; + ret = os_socket_set_ip_add_membership(fd_number(fo), &addr_info, + imr_interface, is_ipv6); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_drop_membership( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, __wasi_addr_ip_t *imr_multiaddr, uint32_t imr_interface) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + bh_ip_addr_buffer_t addr_info; + bool is_ipv6; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info); + is_ipv6 = imr_multiaddr->kind == IPv6; + ret = os_socket_set_ip_drop_membership(fd_number(fo), &addr_info, + imr_interface, is_ipv6); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_multicast_loop( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool ipv6, bool is_enabled) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_set_ip_multicast_loop(fd_number(fo), ipv6, is_enabled); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_get_ip_multicast_loop( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool ipv6, bool *is_enabled) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_get_ip_multicast_loop(fd_number(fo), ipv6, is_enabled); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} 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 ad124c82..7a593390 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 @@ -47,9 +47,13 @@ struct argv_environ_values { }; struct addr_pool { - struct addr_pool *next; /* addr and mask in host order */ - uint32 addr; + union { + uint32 ip4; + uint16 ip6[8]; + } addr; + struct addr_pool *next; + __wasi_addr_type_t type; uint8 mask; }; diff --git a/core/shared/platform/common/posix/posix_socket.c b/core/shared/platform/common/posix/posix_socket.c index d3bcf148..adb7b11d 100644 --- a/core/shared/platform/common/posix/posix_socket.c +++ b/core/shared/platform/common/posix/posix_socket.c @@ -7,29 +7,123 @@ #include "platform_api_extension.h" #include +#include +#include +#include -static void -textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out) +static bool +textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out, + socklen_t *out_len) { + struct sockaddr_in *v4; + struct sockaddr_in6 *v6; + assert(textual); - out->sin_family = AF_INET; - out->sin_port = htons(port); - out->sin_addr.s_addr = inet_addr(textual); + v4 = (struct sockaddr_in *)out; + if (inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) { + v4->sin_family = AF_INET; + v4->sin_port = htons(port); + *out_len = sizeof(struct sockaddr_in); + return true; + } + + v6 = (struct sockaddr_in6 *)out; + if (inet_pton(AF_INET6, textual, &v6->sin6_addr.s6_addr) == 1) { + v6->sin6_family = AF_INET6; + v6->sin6_port = htons(port); + *out_len = sizeof(struct sockaddr_in6); + return true; + } + + return false; +} + +static int +sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen, + bh_sockaddr_t *bh_sockaddr) +{ + switch (sockaddr->sa_family) { + case AF_INET: + { + struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr; + + assert(socklen >= sizeof(struct sockaddr_in)); + + bh_sockaddr->port = ntohs(addr->sin_port); + bh_sockaddr->addr_bufer.ipv4 = ntohl(addr->sin_addr.s_addr); + bh_sockaddr->is_ipv4 = true; + return BHT_OK; + } + case AF_INET6: + { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr; + size_t i; + + assert(socklen >= sizeof(struct sockaddr_in6)); + + bh_sockaddr->port = ntohs(addr->sin6_port); + + for (i = 0; i < sizeof(bh_sockaddr->addr_bufer.ipv6) + / sizeof(bh_sockaddr->addr_bufer.ipv6[0]); + i++) { + uint16 part_addr = addr->sin6_addr.s6_addr[i * 2] + | (addr->sin6_addr.s6_addr[i * 2 + 1] << 8); + bh_sockaddr->addr_bufer.ipv6[i] = ntohs(part_addr); + } + + bh_sockaddr->is_ipv4 = false; + return BHT_OK; + } + default: + errno = EAFNOSUPPORT; + return BHT_ERROR; + } +} + +static void +bh_sockaddr_to_sockaddr(const bh_sockaddr_t *bh_sockaddr, + struct sockaddr_storage *sockaddr, socklen_t *socklen) +{ + if (bh_sockaddr->is_ipv4) { + struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr; + addr->sin_port = htons(bh_sockaddr->port); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = htonl(bh_sockaddr->addr_bufer.ipv4); + *socklen = sizeof(*addr); + } + else { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr; + size_t i; + addr->sin6_port = htons(bh_sockaddr->port); + addr->sin6_family = AF_INET6; + + for (i = 0; i < sizeof(bh_sockaddr->addr_bufer.ipv6) + / sizeof(bh_sockaddr->addr_bufer.ipv6[0]); + i++) { + uint16 part_addr = htons(bh_sockaddr->addr_bufer.ipv6[i]); + addr->sin6_addr.s6_addr[i * 2] = 0xff & part_addr; + addr->sin6_addr.s6_addr[i * 2 + 1] = (0xff00 & part_addr) >> 8; + } + + *socklen = sizeof(*addr); + } } int -os_socket_create(bh_socket_t *sock, int tcp_or_udp) +os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) { + int af = is_ipv4 ? AF_INET : AF_INET6; + if (!sock) { return BHT_ERROR; } - if (1 == tcp_or_udp) { - *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (is_tcp) { + *sock = socket(af, SOCK_STREAM, IPPROTO_TCP); } - else if (0 == tcp_or_udp) { - *sock = socket(AF_INET, SOCK_DGRAM, 0); + else { + *sock = socket(af, SOCK_DGRAM, 0); } return (*sock == -1) ? BHT_ERROR : BHT_OK; @@ -38,7 +132,7 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp) int os_socket_bind(bh_socket_t socket, const char *host, int *port) { - struct sockaddr_in addr; + struct sockaddr_storage addr = { 0 }; struct linger ling; socklen_t socklen; int ret; @@ -59,11 +153,12 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) goto fail; } - addr.sin_addr.s_addr = inet_addr(host); - addr.sin_port = htons(*port); - addr.sin_family = AF_INET; + if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr, + &socklen)) { + goto fail; + } - ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr)); + ret = bind(socket, (struct sockaddr *)&addr, socklen); if (ret < 0) { goto fail; } @@ -73,7 +168,9 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) goto fail; } - *port = ntohs(addr.sin_port); + *port = ntohs(addr.ss_family == AF_INET + ? ((struct sockaddr_in *)&addr)->sin_port + : ((struct sockaddr_in6 *)&addr)->sin6_port); return BHT_OK; @@ -114,7 +211,7 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, struct sockaddr addr_tmp; unsigned int len = sizeof(struct sockaddr); - *sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len); + *sock = accept(server_sock, &addr_tmp, &len); if (*sock < 0) { return BHT_ERROR; @@ -126,11 +223,14 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, 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); + struct sockaddr_storage addr_in = { 0 }; + socklen_t addr_len; int ret = 0; - textual_addr_to_sockaddr(addr, port, &addr_in); + if (!textual_addr_to_sockaddr(addr, port, (struct sockaddr *)&addr_in, + &addr_len)) { + return BHT_ERROR; + } ret = connect(socket, (struct sockaddr *)&addr_in, addr_len); if (ret == -1) { @@ -146,12 +246,48 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) return recv(socket, buf, len, 0); } +int +os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, + bh_sockaddr_t *src_addr) +{ + struct sockaddr_storage sock_addr = { 0 }; + socklen_t socklen = sizeof(sock_addr); + int ret; + + ret = recvfrom(socket, buf, len, flags, (struct sockaddr *)&sock_addr, + &socklen); + + if (ret < 0) { + return ret; + } + + if (src_addr) { + sockaddr_to_bh_sockaddr((struct sockaddr *)&sock_addr, socklen, + src_addr); + } + + return ret; +} + int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) { return send(socket, buf, len, 0); } +int +os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, + int flags, const bh_sockaddr_t *dest_addr) +{ + struct sockaddr_storage sock_addr = { 0 }; + socklen_t socklen = 0; + + bh_sockaddr_to_sockaddr(dest_addr, &sock_addr, &socklen); + + return sendto(socket, buf, len, 0, (const struct sockaddr *)&sock_addr, + socklen); +} + int os_socket_close(bh_socket_t socket) { @@ -167,12 +303,668 @@ os_socket_shutdown(bh_socket_t socket) } int -os_socket_inet_network(const char *cp, uint32 *out) +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) { if (!cp) return BHT_ERROR; - /* Note: ntohl(INADDR_NONE) == INADDR_NONE */ - *out = ntohl(inet_addr(cp)); + if (is_ipv4) { + if (inet_pton(AF_INET, cp, &out->ipv4) != 1) { + return BHT_ERROR; + } + /* Note: ntohl(INADDR_NONE) == INADDR_NONE */ + out->ipv4 = ntohl(out->ipv4); + } + else { + if (inet_pton(AF_INET6, cp, out->ipv6) != 1) { + return BHT_ERROR; + } + for (int i = 0; i < 8; i++) { + out->ipv6[i] = ntohs(out->ipv6[i]); + } + } + return BHT_OK; } + +static int +getaddrinfo_error_to_errno(int error) +{ + switch (error) { + case EAI_AGAIN: + return EAGAIN; + case EAI_FAIL: + return EFAULT; + case EAI_MEMORY: + return ENOMEM; + case EAI_SYSTEM: + return errno; + default: + return EINVAL; + } +} + +static int +is_addrinfo_supported(struct addrinfo *info) +{ + return + // Allow only IPv4 and IPv6 + (info->ai_family == AF_INET || info->ai_family == AF_INET6) + // Allow only UDP and TCP + && (info->ai_socktype == SOCK_DGRAM || info->ai_socktype == SOCK_STREAM) + && (info->ai_protocol == IPPROTO_TCP + || info->ai_protocol == IPPROTO_UDP); +} + +int +os_socket_addr_resolve(const char *host, const char *service, + uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4, + bh_addr_info_t *addr_info, size_t addr_info_size, + size_t *max_info_size) +{ + struct addrinfo hints = { 0 }, *res, *result; + int hints_enabled = hint_is_tcp || hint_is_ipv4; + int ret; + size_t pos = 0; + + if (hints_enabled) { + if (hint_is_ipv4) { + hints.ai_family = *hint_is_ipv4 ? AF_INET : AF_INET6; + } + if (hint_is_tcp) { + hints.ai_socktype = *hint_is_tcp ? SOCK_STREAM : SOCK_DGRAM; + } + } + + ret = getaddrinfo(host, strlen(service) == 0 ? NULL : service, + hints_enabled ? &hints : NULL, &result); + if (ret != BHT_OK) { + errno = getaddrinfo_error_to_errno(ret); + return BHT_ERROR; + } + + res = result; + while (res) { + if (addr_info_size > pos) { + if (!is_addrinfo_supported(res)) { + res = res->ai_next; + continue; + } + + sockaddr_to_bh_sockaddr(res->ai_addr, sizeof(struct sockaddr_in), + &addr_info[pos].sockaddr); + + addr_info[pos].is_tcp = res->ai_socktype == SOCK_STREAM; + } + + pos++; + res = res->ai_next; + } + + *max_info_size = pos; + freeaddrinfo(result); + + return BHT_OK; +} + +static int +os_socket_setbooloption(bh_socket_t socket, int level, int optname, + bool is_enabled) +{ + int option = (int)is_enabled; + if (setsockopt(socket, level, optname, &option, sizeof(option)) != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +static int +os_socket_getbooloption(bh_socket_t socket, int level, int optname, + bool *is_enabled) +{ + assert(is_enabled); + + int optval; + int optval_size = sizeof(optval); + if (getsockopt(socket, level, optname, &optval, &optval_size) != 0) { + return BHT_ERROR; + } + *is_enabled = (bool)optval; + return BHT_OK; +} + +int +os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz) +{ + int buf_size_int = (int)bufsiz; + if (setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buf_size_int, + sizeof(buf_size_int)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz) +{ + assert(bufsiz); + + int buf_size_int; + socklen_t bufsiz_len = sizeof(buf_size_int); + if (getsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buf_size_int, &bufsiz_len) + != 0) { + return BHT_ERROR; + } + *bufsiz = (size_t)buf_size_int; + + return BHT_OK; +} + +int +os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz) +{ + int buf_size_int = (int)bufsiz; + if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &buf_size_int, + sizeof(buf_size_int)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz) +{ + assert(bufsiz); + + int buf_size_int; + socklen_t bufsiz_len = sizeof(buf_size_int); + if (getsockopt(socket, SOL_SOCKET, SO_RCVBUF, &buf_size_int, &bufsiz_len) + != 0) { + return BHT_ERROR; + } + *bufsiz = (size_t)buf_size_int; + + return BHT_OK; +} + +int +os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled) +{ + return os_socket_setbooloption(socket, SOL_SOCKET, SO_KEEPALIVE, + is_enabled); +} + +int +os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled) +{ + return os_socket_getbooloption(socket, SOL_SOCKET, SO_KEEPALIVE, + is_enabled); +} + +int +os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled) +{ + return os_socket_setbooloption(socket, SOL_SOCKET, SO_REUSEADDR, + is_enabled); +} + +int +os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled) +{ + return os_socket_getbooloption(socket, SOL_SOCKET, SO_REUSEADDR, + is_enabled); +} + +int +os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled) +{ + return os_socket_setbooloption(socket, SOL_SOCKET, SO_REUSEPORT, + is_enabled); +} + +int +os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled) +{ + return os_socket_getbooloption(socket, SOL_SOCKET, SO_REUSEPORT, + is_enabled); +} + +int +os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s) +{ + struct linger linger_opts = { .l_onoff = (int)is_enabled, + .l_linger = linger_s }; + if (setsockopt(socket, SOL_SOCKET, SO_LINGER, &linger_opts, + sizeof(linger_opts)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s) +{ + assert(is_enabled); + assert(linger_s); + + struct linger linger_opts; + socklen_t linger_opts_len = sizeof(linger_opts); + if (getsockopt(socket, SOL_SOCKET, SO_LINGER, &linger_opts, + &linger_opts_len) + != 0) { + return BHT_ERROR; + } + *linger_s = linger_opts.l_linger; + *is_enabled = (bool)linger_opts.l_onoff; + return BHT_OK; +} + +int +os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled) +{ + return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_NODELAY, + is_enabled); +} + +int +os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled) +{ + return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_NODELAY, + is_enabled); +} + +int +os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled) +{ +#ifdef TCP_QUICKACK + return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_QUICKACK, + is_enabled); +#else + errno = ENOSYS; + + return BHT_ERROR; +#endif +} + +int +os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled) +{ +#ifdef TCP_QUICKACK + return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_QUICKACK, + is_enabled); +#else + errno = ENOSYS; + + return BHT_ERROR; +#endif +} + +int +os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s) +{ + int time_s_int = (int)time_s; +#ifdef TCP_KEEPIDLE + if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &time_s_int, + sizeof(time_s_int)) + != 0) { + return BHT_ERROR; + } + return BHT_OK; +#elif defined(TCP_KEEPALIVE) + if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &time_s_int, + sizeof(time_s_int)) + != 0) { + return BHT_ERROR; + } + return BHT_OK; +#else + errno = ENOSYS; + + return BHT_ERROR; +#endif +} + +int +os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s) +{ + assert(time_s); + int time_s_int; + socklen_t time_s_len = sizeof(time_s_int); +#ifdef TCP_KEEPIDLE + if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &time_s_int, &time_s_len) + != 0) { + return BHT_ERROR; + } + *time_s = (uint32)time_s_int; + return BHT_OK; +#elif defined(TCP_KEEPALIVE) + if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &time_s_int, &time_s_len) + != 0) { + return BHT_ERROR; + } + *time_s = (uint32)time_s_int; + return BHT_OK; +#else + errno = ENOSYS; + + return BHT_ERROR; +#endif +} + +int +os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s) +{ + int time_s_int = (int)time_s; +#ifdef TCP_KEEPINTVL + if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &time_s_int, + sizeof(time_s_int)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +#else + errno = ENOSYS; + + return BHT_ERROR; +#endif +} + +int +os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s) +{ +#ifdef TCP_KEEPINTVL + assert(time_s); + int time_s_int; + socklen_t time_s_len = sizeof(time_s_int); + if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &time_s_int, &time_s_len) + != 0) { + return BHT_ERROR; + } + *time_s = (uint32)time_s_int; + return BHT_OK; +#else + errno = ENOSYS; + + return BHT_ERROR; +#endif +} + +int +os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled) +{ +#ifdef TCP_FASTOPEN_CONNECT + return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, + is_enabled); +#else + errno = ENOSYS; + + return BHT_ERROR; +#endif +} + +int +os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled) +{ +#ifdef TCP_FASTOPEN_CONNECT + return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, + is_enabled); +#else + errno = ENOSYS; + + return BHT_ERROR; +#endif +} + +int +os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) +{ + if (ipv6) { + return os_socket_setbooloption(socket, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, is_enabled); + } + else { + return os_socket_setbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP, + is_enabled); + } +} + +int +os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled) +{ + if (ipv6) { + return os_socket_getbooloption(socket, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, is_enabled); + } + else { + return os_socket_getbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP, + is_enabled); + } +} + +int +os_socket_set_ip_add_membership(bh_socket_t socket, + bh_ip_addr_buffer_t *imr_multiaddr, + uint32_t imr_interface, bool is_ipv6) +{ + assert(imr_multiaddr); + if (is_ipv6) { + struct ipv6_mreq mreq; + for (int i = 0; i < 8; i++) { + ((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] = + imr_multiaddr->ipv6[i]; + } + mreq.ipv6mr_interface = imr_interface; + if (setsockopt(socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, + sizeof(mreq)) + != 0) { + return BHT_ERROR; + } + } + else { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4; + mreq.imr_interface.s_addr = imr_interface; + if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) + != 0) { + return BHT_ERROR; + } + } + + return BHT_OK; +} + +int +os_socket_set_ip_drop_membership(bh_socket_t socket, + bh_ip_addr_buffer_t *imr_multiaddr, + uint32_t imr_interface, bool is_ipv6) +{ + assert(imr_multiaddr); + if (is_ipv6) { + struct ipv6_mreq mreq; + for (int i = 0; i < 8; i++) { + ((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] = + imr_multiaddr->ipv6[i]; + } + mreq.ipv6mr_interface = imr_interface; + if (setsockopt(socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, + sizeof(mreq)) + != 0) { + return BHT_ERROR; + } + } + else { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4; + mreq.imr_interface.s_addr = imr_interface; + if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, + sizeof(mreq)) + != 0) { + return BHT_ERROR; + } + } + + return BHT_OK; +} + +int +os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s) +{ + if (setsockopt(socket, IPPROTO_IP, IP_TTL, &ttl_s, sizeof(ttl_s)) != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s) +{ + socklen_t opt_len = sizeof(ttl_s); + if (getsockopt(socket, IPPROTO_IP, IP_TTL, ttl_s, &opt_len) != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s) +{ + if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl_s, sizeof(ttl_s)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) +{ + socklen_t opt_len = sizeof(ttl_s); + if (getsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, ttl_s, &opt_len) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_set_ipv6_only(bh_socket_t socket, bool is_enabled) +{ + return os_socket_setbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY, + is_enabled); +} + +int +os_socket_get_ipv6_only(bh_socket_t socket, bool *is_enabled) +{ + return os_socket_getbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY, + is_enabled); +} + +int +os_socket_set_broadcast(bh_socket_t socket, bool is_enabled) +{ + return os_socket_setbooloption(socket, SOL_SOCKET, SO_BROADCAST, + is_enabled); +} + +int +os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled) +{ + return os_socket_getbooloption(socket, SOL_SOCKET, SO_BROADCAST, + is_enabled); +} + +int +os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) +{ + struct timeval tv; + tv.tv_sec = timeout_us / 1000000UL; + tv.tv_usec = timeout_us % 1000000UL; + if (setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) { + return BHT_ERROR; + } + return BHT_OK; +} + +int +os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + struct timeval tv; + socklen_t tv_len = sizeof(tv); + if (getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, &tv_len) != 0) { + return BHT_ERROR; + } + *timeout_us = (tv.tv_sec * 1000000UL) + tv.tv_usec; + return BHT_OK; +} + +int +os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) +{ + struct timeval tv; + tv.tv_sec = timeout_us / 1000000UL; + tv.tv_usec = timeout_us % 1000000UL; + if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) { + return BHT_ERROR; + } + return BHT_OK; +} + +int +os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + struct timeval tv; + socklen_t tv_len = sizeof(tv); + if (getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, &tv_len) != 0) { + return BHT_ERROR; + } + *timeout_us = (tv.tv_sec * 1000000UL) + tv.tv_usec; + return BHT_OK; +} + +int +os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) +{ + struct sockaddr_storage addr_storage = { 0 }; + socklen_t addr_len = sizeof(addr_storage); + int ret; + + ret = getsockname(socket, (struct sockaddr *)&addr_storage, &addr_len); + + if (ret != BHT_OK) { + return BHT_ERROR; + } + + return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len, + sockaddr); +} + +int +os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) +{ + struct sockaddr_storage addr_storage = { 0 }; + socklen_t addr_len = sizeof(addr_storage); + int ret; + + ret = getpeername(socket, (struct sockaddr *)&addr_storage, &addr_len); + + if (ret != BHT_OK) { + return BHT_ERROR; + } + + return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len, + sockaddr); +} \ 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 4a12c7eb..c214c88f 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -292,16 +292,29 @@ os_sem_unlink(const char *name); * need to implement these APIs */ +typedef union { + uint32 ipv4; + uint16 ipv6[8]; + uint8 data[1]; +} bh_ip_addr_buffer_t; + +typedef struct { + bh_ip_addr_buffer_t addr_bufer; + uint16 port; + bool is_ipv4; +} bh_sockaddr_t; + /** * Create a socket * * @param sock [OUTPUT] the pointer of socket - * @param tcp_or_udp 1 for tcp, 0 for udp + * @param is_ipv4 true for IPv4, false for IPv6 + * @param is_tcp true for tcp, false for udp * * @return 0 if success, -1 otherwise */ int -os_socket_create(bh_socket_t *sock, int tcp_or_udp); +os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp); /** * Assign the address and port to the socket @@ -380,6 +393,22 @@ os_socket_connect(bh_socket_t socket, const char *addr, int port); int os_socket_recv(bh_socket_t socket, void *buf, unsigned int len); +/** + * Blocking receive message from a socket. + * + * @param socket the socket to send message + * @param buf the buffer to store the data + * @param len length of the buffer, this API does not guarantee that + * [len] bytes are received + * @param flags control the operation + * @param src_addr source address + * + * @return number of bytes sent if success, -1 otherwise + */ +int +os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, + bh_sockaddr_t *src_addr); + /** * Blocking send message on a socket * @@ -392,6 +421,21 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len); int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len); +/** + * Blocking send message on a socket to the target address + * + * @param socket the socket to send message + * @param buf the buffer of data to be sent + * @param len length of the buffer + * @param flags control the operation + * @param dest_addr target address + * + * @return number of bytes sent if success, -1 otherwise + */ +int +os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, + int flags, const bh_sockaddr_t *dest_addr); + /** * Close a socket * @@ -416,13 +460,522 @@ 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 + * @param is_ipv4 a flag that indicates whether the string is an IPv4 or + * IPv6 address * - * @return On success, the converted address is returned. + * @param cp a string in IPv4 numbers-and-dots notation or IPv6 + * numbers-and-colons notation + * + * @param out an output buffer to store binary address + * + * @return On success, the function returns 0. * If the input is invalid, -1 is returned */ int -os_socket_inet_network(const char *cp, uint32 *out); +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out); + +typedef struct { + bh_sockaddr_t sockaddr; + uint8_t is_tcp; +} bh_addr_info_t; + +/** + * Resolve a host a hostname and a service to one or more IP addresses + * + * @param host a host to resolve + * + * @param service a service to find a port for + * + * @param hint_is_tcp an optional flag that determines a preferred socket type + (TCP or UDP). + * + * @param hint_is_ipv4 an optional flag that determines a preferred address + family (IPv4 or IPv6) + * + * @param addr_info a buffer for resolved addresses + * + * @param addr_info_size a size of the buffer for resolved addresses + + * @param max_info_size a maximum number of addresses available (can be bigger + or smaller than buffer size) + + * @return On success, the function returns 0; otherwise, it returns -1 + */ +int +os_socket_addr_resolve(const char *host, const char *service, + uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4, + bh_addr_info_t *addr_info, size_t addr_info_size, + size_t *max_info_size); + +/** + * Returns an binary address and a port of the local socket + * + * @param socket the local socket + * + * @param sockaddr a buffer for storing the address + * + * @return On success, returns 0; otherwise, it returns -1. + */ +int +os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr); + +/** + * Returns an binary address and a port of the remote socket + * + * @param socket the remote socket + * + * @param sockaddr a buffer for storing the address + * + * @return On success, returns 0; otherwise, it returns -1. + */ +int +os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr); + +/** + * Set the maximum send buffer size. + * + * @param socket the socket to set + * @param bufsiz requested kernel buffer size + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz); + +/** + * Get the maximum send buffer size. + * + * @param socket the socket to set + * @param bufsiz the returned kernel buffer size + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz); + +/** + * Set the maximum receive buffer size. + * + * @param socket the socket to set + * @param bufsiz requested kernel buffer size + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz); + +/** + * Get the maximum receive buffer size. + * + * @param socket the socket to set + * @param bufsiz the returned kernel buffer size + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz); + +/** + * Enable sending of keep-alive messages on connection-oriented sockets + * + * @param socket the socket to set the flag + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled); + +/** + * Get if sending of keep-alive messages on connection-oriented sockets is + * enabled + * + * @param socket the socket to check + * @param is_enabled 1 if enabled or 0 if disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled); + +/** + * Set the send timeout until reporting an error + * + * @param socket the socket to set + * @param time_us microseconds until timeout + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us); + +/** + * Get the send timeout until reporting an error + * + * @param socket the socket to set + * @param time_us the returned microseconds until timeout + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us); + +/** + * Set the recv timeout until reporting an error + * + * @param socket the socket to set + * @param time_us microseconds until timeout + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us); + +/** + * Get the recv timeout until reporting an error + * + * @param socket the socket to set + * @param time_us the returned microseconds until timeout + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us); + +/** + * Enable re-use of local addresses + * + * @param socket the socket to set + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled); + +/** + * Get whether re-use of local addresses is enabled + * + * @param socket the socket to set + * @param is_enabled 1 for enabled or 0 for disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled); + +/** + * Enable re-use of local ports + * + * @param socket the socket to set + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled); + +/** + * Get whether re-use of local ports is enabled + * + * @param socket the socket to set + * @param is_enabled 1 for enabled or 0 for disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled); + +/** + * Set the linger options for the given socket + * + * @param socket the socket to set + * @param is_enabled whether linger is enabled + * @param linger_s linger time (seconds) + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s); + +/** + * Get the linger options for the given socket + * + * @param socket the socket to get + * @param is_enabled whether linger is enabled + * @param linger_s linger time (seconds) + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s); + +/** + * Set no delay TCP + * If set, disable the Nagle algorithm. + * This means that segments are always sent as soon as possible, + * even if there is only a small amount of data + * + * @param socket the socket to set the flag + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled); + +/** + * Get no delay TCP + * If set, disable the Nagle algorithm. + * This means that segments are always sent as soon as possible, + * even if there is only a small amount of data + * + * @param socket the socket to check + * @param is_enabled 1 if enabled or 0 if disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled); + +/** + * Enable/Disable tcp quickack mode + * In quickack mode, acks are sent immediately, rather than delayed if needed in + * accordance to normal TCP operation + * + * @param socket the socket to set the flag + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled); + +/** + * Enable/Disable tcp quickack mode + * In quickack mode, acks are sent immediately, rather than delayed if needed in + * accordance to normal TCP operation + * + * @param socket the socket to check + * @param is_enabled 1 if enabled or 0 if disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled); + +/** + * Set the time the connection needs to remain idle before sending keepalive + * probes + * + * @param socket the socket to set + * @param time_s seconds until keepalive probes are sent + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32_t time_s); + +/** + * Gets the time the connection needs to remain idle before sending keepalive + * probes + * + * @param socket the socket to check + * @param time_s seconds until keepalive probes are sent + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32_t *time_s); + +/** + * Set the time between individual keepalive probes + * + * @param socket the socket to set + * @param time_us seconds between individual keepalive probes + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32_t time_s); + +/** + * Get the time between individual keepalive probes + * + * @param socket the socket to get + * @param time_s seconds between individual keepalive probes + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32_t *time_s); + +/** + * Set use of TCP Fast Open + * + * @param socket the socket to set + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled); + +/** + * Get whether use of TCP Fast Open is enabled + * + * @param socket the socket to get + * @param is_enabled 1 to enabled or 0 to disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled); + +/** + * Set enable or disable IPv4 or IPv6 multicast loopback. + * + * @param socket the socket to set + * @param ipv6 true to set ipv6 loopback or false for ipv4 + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled); + +/** + * Get enable or disable IPv4 or IPv6 multicast loopback. + * + * @param socket the socket to check + * @param ipv6 true to set ipv6 loopback or false for ipv4 + * @param is_enabled 1 for enabled or 0 for disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, + bool *is_enabled); + +/** + * Add membership to a group + * + * @param socket the socket to add membership to + * @param imr_multiaddr the group multicast address (IPv4 or IPv6) + * @param imr_interface the interface to join on + * @param is_ipv6 whether the imr_multiaddr is IPv4 or IPv6 (true for IPv6) + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_ip_add_membership(bh_socket_t socket, + bh_ip_addr_buffer_t *imr_multiaddr, + uint32_t imr_interface, bool is_ipv6); + +/** + * Drop membership of a group + * + * @param socket the socket to drop membership to + * @param imr_multiaddr the group multicast address (IPv4 or IPv6) + * @param imr_interface the interface to join on + * @param is_ipv6 whether the imr_multiaddr is IPv4 or IPv6 (true for IPv6) + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_ip_drop_membership(bh_socket_t socket, + bh_ip_addr_buffer_t *imr_multiaddr, + uint32_t imr_interface, bool is_ipv6); + +/** + * Set the current time-to-live field that is + * used in every packet sent from this socket. + * @param socket the socket to set the flag + * @param ttl_s time to live (seconds) + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s); + +/** + * Retrieve the current time-to-live field that is + * used in every packet sent from this socket. + * @param socket the socket to set the flag + * @param ttl_s time to live (seconds) + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s); + +/** + * Set the time-to-live value of outgoing multicast + * packets for this socket + * @param socket the socket to set the flag + * @param ttl_s time to live (seconds) + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s); + +/** + * Read the time-to-live value of outgoing multicast + * packets for this socket + * @param socket the socket to set the flag + * @param ttl_s time to live (seconds) + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s); + +/** + * Restrict to sending and receiving IPv6 packets only + * + * @param socket the socket to set + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_ipv6_only(bh_socket_t socket, bool is_enabled); + +/** + * Get whether only sending and receiving IPv6 packets + * + * @param socket the socket to check + * @param is_enabled 1 for enabled or 0 for disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_ipv6_only(bh_socket_t socket, bool *is_enabled); + +/** + * Set whether broadcast is enabled + * When enabled, datagram sockets are allowed + * to send packets to a broadcast address. + * + * @param socket the socket to set the flag + * @param is_enabled 1 to enable or 0 to disable + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_broadcast(bh_socket_t socket, bool is_enabled); + +/** + * Get whether broadcast is enabled + * When enabled, datagram sockets are allowed + * to send packets to a broadcast address. + * + * @param socket the socket to check + * @param is_enabled 1 if enabled or 0 if disabled + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled); #ifdef __cplusplus } diff --git a/core/shared/platform/linux-sgx/sgx_socket.c b/core/shared/platform/linux-sgx/sgx_socket.c index 156d79ef..2911cd3c 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.c +++ b/core/shared/platform/linux-sgx/sgx_socket.c @@ -4,6 +4,7 @@ */ #include "platform_api_vmcore.h" +#include "platform_api_extension.h" #ifndef SGX_DISABLE_WASI @@ -91,7 +92,7 @@ swap16(uint8 *pData) *(pData + 1) = value; } -static uint32 +uint32 htonl(uint32 value) { uint32 ret; @@ -104,13 +105,13 @@ htonl(uint32 value) return value; } -static uint32 +uint32 ntohl(uint32 value) { return htonl(value); } -static uint16 +uint16 htons(uint16 value) { uint16 ret; @@ -131,57 +132,96 @@ ntohs(uint16 value) /* Coming from musl, under MIT license */ static int -__inet_aton(const char *s0, struct in_addr *dest) +hexval(unsigned c) { - const char *s = s0; - unsigned char *d = (void *)dest; - unsigned long a[4] = { 0 }; - char *z; - int i; - - for (i = 0; i < 4; i++) { - a[i] = strtoul(s, &z, 0); - if (z == s || (*z && *z != '.') || !isdigit(*s)) - return 0; - if (!*z) - break; - s = z + 1; - } - if (i == 4) - return 0; - switch (i) { - case 0: - a[1] = a[0] & 0xffffff; - a[0] >>= 24; - case 1: - a[2] = a[1] & 0xffff; - a[1] >>= 16; - case 2: - a[3] = a[2] & 0xff; - a[2] >>= 8; - } - for (i = 0; i < 4; i++) { - if (a[i] > 255) - return 0; - d[i] = a[i]; - } - return 1; + if (c - '0' < 10) + return c - '0'; + c |= 32; + if (c - 'a' < 6) + return c - 'a' + 10; + return -1; } /* Coming from musl, under MIT license */ static int -inet_addr(const char *p) +inet_pton(int af, const char *restrict s, void *restrict a0) { - struct in_addr a; - if (!__inet_aton(p, &a)) + uint16_t ip[8]; + unsigned char *a = a0; + int i, j, v, d, brk = -1, need_v4 = 0; + + if (af == AF_INET) { + for (i = 0; i < 4; i++) { + for (v = j = 0; j < 3 && isdigit(s[j]); j++) + v = 10 * v + s[j] - '0'; + if (j == 0 || (j > 1 && s[0] == '0') || v > 255) + return 0; + a[i] = v; + if (s[j] == 0 && i == 3) + return 1; + if (s[j] != '.') + return 0; + s += j + 1; + } + return 0; + } + else if (af != AF_INET6) { + errno = EAFNOSUPPORT; return -1; - return a.s_addr; + } + + if (*s == ':' && *++s != ':') + return 0; + + for (i = 0;; i++) { + if (s[0] == ':' && brk < 0) { + brk = i; + ip[i & 7] = 0; + if (!*++s) + break; + if (i == 7) + return 0; + continue; + } + for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++) + v = 16 * v + d; + if (j == 0) + return 0; + ip[i & 7] = v; + if (!s[j] && (brk >= 0 || i == 7)) + break; + if (i == 7) + return 0; + if (s[j] != ':') { + if (s[j] != '.' || (i < 6 && brk < 0)) + return 0; + need_v4 = 1; + i++; + break; + } + s += j + 1; + } + if (brk >= 0) { + memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk)); + for (j = 0; j < 7 - i; j++) + ip[brk + j] = 0; + } + for (j = 0; j < 8; j++) { + *a++ = ip[j] >> 8; + *a++ = ip[j]; + } + if (need_v4 && inet_pton(AF_INET, (void *)s, a - 4) <= 0) + return 0; + return 1; } static int -inet_network(const char *p) +inet_addr(const char *p) { - return ntohl(inet_addr(p)); + struct in_addr a; + if (!inet_pton(AF_INET, p, &a)) + return -1; + return a.s_addr; } /** In-enclave implementation of POSIX functions end **/ @@ -527,21 +567,30 @@ os_socket_connect(bh_socket_t socket, const char *addr, int port) } int -os_socket_create(bh_socket_t *sock, int tcp_or_udp) +os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) { + int af; + if (!sock) { return BHT_ERROR; } - if (1 == tcp_or_udp) { - if (ocall_socket(sock, AF_INET, SOCK_STREAM, IPPROTO_TCP) - != SGX_SUCCESS) { + if (is_ipv4) { + af = AF_INET; + } + else { + errno = ENOSYS; + return BHT_ERROR; + } + + if (is_tcp) { + if (ocall_socket(sock, af, SOCK_STREAM, IPPROTO_TCP) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); return -1; } } - else if (0 == tcp_or_udp) { - if (ocall_socket(sock, AF_INET, SOCK_DGRAM, 0) != SGX_SUCCESS) { + else { + if (ocall_socket(sock, af, SOCK_DGRAM, 0) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); return -1; } @@ -556,12 +605,26 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp) } int -os_socket_inet_network(const char *cp, uint32 *out) +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) { if (!cp) return BHT_ERROR; - *out = inet_network(cp); + if (is_ipv4) { + if (inet_pton(AF_INET, cp, &out->ipv4) != 1) { + return BHT_ERROR; + } + /* Note: ntohl(INADDR_NONE) == INADDR_NONE */ + out->ipv4 = ntohl(out->ipv4); + } + else { + if (inet_pton(AF_INET6, cp, out->ipv6) != 1) { + return BHT_ERROR; + } + for (int i = 0; i < 8; i++) { + out->ipv6[i] = ntohs(out->ipv6[i]); + } + } return BHT_OK; } @@ -598,6 +661,15 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) return ret; } +int +os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, + bh_sockaddr_t *src_addr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) { @@ -614,10 +686,354 @@ os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) return ret; } +int +os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, + int flags, const bh_sockaddr_t *dest_addr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_shutdown(bh_socket_t socket) { return shutdown(socket, O_RDWR); } +int +os_socket_addr_resolve(const char *host, const char *service, + uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4, + bh_addr_info_t *addr_info, size_t addr_info_size, + size_t *max_info_size) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_add_membership(bh_socket_t socket, + bh_ip_addr_buffer_t *imr_multiaddr, + uint32_t imr_interface, bool is_ipv6) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_drop_membership(bh_socket_t socket, + bh_ip_addr_buffer_t *imr_multiaddr, + uint32_t imr_interface, bool is_ipv6) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ipv6_only(bh_socket_t socket, bool option) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_ipv6_only(bh_socket_t socket, bool *option) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_broadcast(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + #endif diff --git a/core/shared/platform/linux-sgx/sgx_socket.h b/core/shared/platform/linux-sgx/sgx_socket.h index 7dc05fce..6339b15d 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.h +++ b/core/shared/platform/linux-sgx/sgx_socket.h @@ -46,7 +46,8 @@ extern "C" { #define SHUT_RDWR 2 /* Address families. */ -#define AF_INET 2 /* IP protocol family. */ +#define AF_INET 2 /* IP protocol family. */ +#define AF_INET6 10 /* IP version 6. */ /* Standard well-defined IP protocols. */ #define IPPROTO_TCP 6 /* Transmission Control Protocol. */ @@ -95,6 +96,15 @@ struct sockaddr { char sa_data[14]; /* Address data. */ }; +uint32_t +ntohl(uint32_t value); + +uint32_t +htonl(uint32_t value); + +uint16_t +htons(uint16_t value); + int socket(int domain, int type, int protocol); diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index 2bf7a84f..9a1c7a3c 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -37,17 +37,27 @@ deinit_winsock() } int -os_socket_create(bh_socket_t *sock, int tcp_or_udp) +os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) { + int af; + if (!sock) { return BHT_ERROR; } - if (1 == tcp_or_udp) { - *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (is_ipv4) { + af = AF_INET; } - else if (0 == tcp_or_udp) { - *sock = socket(AF_INET, SOCK_DGRAM, 0); + else { + errno = ENOSYS; + return BHT_ERROR; + } + + if (is_tcp) { + *sock = socket(af, SOCK_STREAM, IPPROTO_TCP); + } + else { + *sock = socket(af, SOCK_DGRAM, 0); } return (*sock == -1) ? BHT_ERROR : BHT_OK; @@ -133,12 +143,30 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) return recv(socket, buf, len, 0); } +int +os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, + bh_sockaddr_t *src_addr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) { return send(socket, buf, len, 0); } +int +os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, + int flags, const bh_sockaddr_t *dest_addr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_close(bh_socket_t socket) { @@ -154,11 +182,360 @@ os_socket_shutdown(bh_socket_t socket) } int -os_socket_inet_network(const char *cp, uint32 *out) +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) { if (!cp) return BHT_ERROR; - *out = inet_addr(cp); + if (is_ipv4) { + if (inet_pton(AF_INET, cp, &out->ipv4) != 1) { + return BHT_ERROR; + } + /* Note: ntohl(INADDR_NONE) == INADDR_NONE */ + out->ipv4 = ntohl(out->ipv4); + } + else { + if (inet_pton(AF_INET6, cp, out->ipv6) != 1) { + return BHT_ERROR; + } + for (int i = 0; i < 8; i++) { + out->ipv6[i] = ntohs(out->ipv6[i]); + } + } + return BHT_OK; -} \ No newline at end of file +} + +int +os_socket_addr_resolve(const char *host, const char *service, + uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4, + bh_addr_info_t *addr_info, size_t addr_info_size, + size_t *max_info_size) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_add_membership(bh_socket_t socket, + bh_ip_addr_buffer_t *imr_multiaddr, + uint32_t imr_interface, bool is_ipv6) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_drop_membership(bh_socket_t socket, + bh_ip_addr_buffer_t *imr_multiaddr, + uint32_t imr_interface, bool is_ipv6) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_ipv6_only(bh_socket_t socket, bool option) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_ipv6_only(bh_socket_t socket, bool *option) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_broadcast(bh_socket_t socket, bool is_enabled) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled) +{ + errno = ENOSYS; + return BHT_ERROR; +} diff --git a/doc/socket_api.md b/doc/socket_api.md index 203a0e64..cdf7494c 100644 --- a/doc/socket_api.md +++ b/doc/socket_api.md @@ -64,6 +64,14 @@ should be announced first. Every IP address should be in CIRD notation. $ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm ``` +_iwasm_ also accepts list of domain names and domain name patterns for the address resolution via an option, `--allow-resolve`, to implement the capability control. Every domain that will be resolved using `sock_addr_resolve` needs to be added to the allowlist first. + +```bash +$ iwasm --allow-resolve=*.example.com --allow-resolve=domain.com +``` + +The example above shows how to allow for resolving all `example.com`'s subdomains (e.g. `x.example.com`, `a.b.c.example.com`) and `domain.com` domain. + Refer to [socket api sample](../samples/socket-api) for more details. ## Intel SGX support diff --git a/language-bindings/go/wamr/module.go b/language-bindings/go/wamr/module.go index a637e084..9d6b7d94 100644 --- a/language-bindings/go/wamr/module.go +++ b/language-bindings/go/wamr/module.go @@ -132,3 +132,16 @@ func (self *Module) SetWasiAddrPool(addrPool [][]byte) { } C.wasm_runtime_set_wasi_addr_pool(self.module, addrPoolPtr, addrPoolSize) } + +/* Set module's wasi domain lookup pool */ +func(self *Module) SetWasiNsLookupPool(nsLookupPool[][] byte) +{ + var nsLookupPoolPtr **C.char + var nsLookupPoolSize C.uint + + if (nsLookupPool != nil) { + nsLookupPoolPtr = (**C.char)(unsafe.Pointer(&nsLookupPool[0])) + nsLookupPoolSize = C.uint(len(nsLookupPool)) + } + C.wasm_runtime_set_wasi_ns_lookup_pool(self.module, nsLookupPoolPtr, nsLookupPoolSize) +} \ No newline at end of file diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index 2b306417..4834fd50 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -26,49 +26,54 @@ print_help() { printf("Usage: iwasm [-options] wasm_file [args...]\n"); printf("options:\n"); - printf(" -f|--function name Specify a function name of the module to run rather\n" - " than main\n"); + printf(" -f|--function name Specify a function name of the module to run rather\n" + " than main\n"); #if WASM_ENABLE_LOG != 0 - printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" - " level with more log\n"); + printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" + " level with more log\n"); #endif - printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); - printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); + printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); + printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); #if WASM_ENABLE_FAST_JIT != 0 - printf(" --jit-codecache-size=n Set fast jit maximum code cache size in bytes,\n"); - printf(" default is %u KB\n", FAST_JIT_DEFAULT_CODE_CACHE_SIZE / 1024); + printf(" --jit-codecache-size=n Set fast jit maximum code cache size in bytes,\n"); + printf(" default is %u KB\n", FAST_JIT_DEFAULT_CODE_CACHE_SIZE / 1024); #endif - printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" - " that runs commands in the form of \"FUNC ARG...\"\n"); + printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" + " that runs commands in the form of \"FUNC ARG...\"\n"); #if WASM_ENABLE_LIBC_WASI != 0 - printf(" --env= Pass wasi environment variables with \"key=value\"\n"); - printf(" to the program, for example:\n"); - printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); - 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= 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"); + printf(" --env= Pass wasi environment variables with \"key=value\"\n"); + printf(" to the program, for example:\n"); + printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); + 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= 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"); + printf(" --allow-resolve= Allow the lookup of the specific domain name or domain\n"); + printf(" name suffixes using a wildcard, for example:\n"); + printf(" --allow-resolve=example.com # allow the lookup of the specific domain\n"); + printf(" --allow-resolve=*.example.com # allow the lookup of all subdomains\n"); + printf(" --allow-resolve=* # allow any lookup\n"); #endif #if BH_HAS_DLFCN - printf(" --native-lib= Register native libraries to the WASM module, which\n"); - printf(" are shared object (.so) files, for example:\n"); - printf(" --native-lib=test1.so --native-lib=test2.so\n"); + printf(" --native-lib= Register native libraries to the WASM module, which\n"); + printf(" are shared object (.so) files, for example:\n"); + printf(" --native-lib=test1.so --native-lib=test2.so\n"); #endif #if WASM_ENABLE_MULTI_MODULE != 0 - printf(" --module-path= Indicate a module search path. default is current\n" - " directory('./')\n"); + printf(" --module-path= Indicate a module search path. default is current\n" + " directory('./')\n"); #endif #if WASM_ENABLE_LIB_PTHREAD != 0 - printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); + printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); #endif #if WASM_ENABLE_DEBUG_INTERP != 0 - printf(" -g=ip:port Set the debug sever address, default is debug disabled\n"); - printf(" if port is 0, then a random port will be used\n"); + printf(" -g=ip:port Set the debug sever address, default is debug disabled\n"); + printf(" if port is 0, then a random port will be used\n"); #endif - printf(" --version Show version information\n"); + printf(" --version Show version information\n"); return 1; } /* clang-format on */ @@ -316,6 +321,8 @@ main(int argc, char *argv[]) uint32 env_list_size = 0; const char *addr_pool[8] = { NULL }; uint32 addr_pool_size = 0; + const char *ns_lookup_pool[8] = { NULL }; + uint32 ns_lookup_pool_size = 0; #endif #if BH_HAS_DLFCN const char *native_lib_list[8] = { NULL }; @@ -415,6 +422,18 @@ main(int argc, char *argv[]) token = strtok(NULL, ";"); } } + else if (!strncmp(argv[0], "--allow-resolve=", 16)) { + if (argv[0][16] == '\0') + return print_help(); + if (ns_lookup_pool_size + >= sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0])) { + printf( + "Only allow max ns lookup number %d\n", + (int)(sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0]))); + return 1; + } + ns_lookup_pool[ns_lookup_pool_size++] = argv[0] + 16; + } #endif /* WASM_ENABLE_LIBC_WASI */ #if BH_HAS_DLFCN else if (!strncmp(argv[0], "--native-lib=", 13)) { @@ -555,6 +574,8 @@ main(int argc, char *argv[]) env_list, env_list_size, argv, argc); wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, addr_pool_size); + wasm_runtime_set_wasi_ns_lookup_pool(wasm_module, ns_lookup_pool, + ns_lookup_pool_size); #endif /* instantiate the module */ diff --git a/samples/socket-api/CMakeLists.txt b/samples/socket-api/CMakeLists.txt index 2508ac7c..193eb264 100644 --- a/samples/socket-api/CMakeLists.txt +++ b/samples/socket-api/CMakeLists.txt @@ -90,6 +90,9 @@ ExternalProject_Add(wasm-app tcp_client.wasm ${CMAKE_BINARY_DIR} tcp_server.wasm ${CMAKE_BINARY_DIR} send_recv.wasm ${CMAKE_BINARY_DIR} + socket_opts.wasm ${CMAKE_BINARY_DIR} + udp_client.wasm ${CMAKE_BINARY_DIR} + udp_server.wasm ${CMAKE_BINARY_DIR} ) add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c) @@ -100,6 +103,14 @@ add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c) add_executable(send_recv ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/send_recv.c) target_link_libraries(send_recv pthread) +add_executable(addr_resolve ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/addr_resolve.c) + +add_executable(socket_opts ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/socket_opts.c) + +add_executable(udp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/udp_client.c) + +add_executable(udp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/udp_server.c) + ############################################ ## Build iwasm with wasi and pthread support ############################################ diff --git a/samples/socket-api/README.md b/samples/socket-api/README.md index 71f62ca8..5260e851 100644 --- a/samples/socket-api/README.md +++ b/samples/socket-api/README.md @@ -82,4 +82,20 @@ Data: And mourns for us ``` +`socket_opts.wasm` shows an example of getting and setting various supported socket options +```bash +$ ./iwasm ./socket_opts.wasm +``` + +The output describes the different socket options that are set & retrieved, like so: +```bash +[Client] Create TCP socket +[Client] Create UDP socket +[Client] Create UDP IPv6 socket +SO_RCVTIMEO tv_sec is expected +SO_RCVTIMEO tv_usec is expected +... +[Client] Close sockets +``` + 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 5c0ed7e2..32cd7276 100644 --- a/samples/socket-api/wasm-src/CMakeLists.txt +++ b/samples/socket-api/wasm-src/CMakeLists.txt @@ -79,3 +79,7 @@ endfunction() compile_with_clang(tcp_server.c) compile_with_clang(tcp_client.c) compile_with_clang(send_recv.c) +compile_with_clang(addr_resolve.c) +compile_with_clang(socket_opts.c) +compile_with_clang(udp_client.c) +compile_with_clang(udp_server.c) diff --git a/samples/socket-api/wasm-src/addr_resolve.c b/samples/socket-api/wasm-src/addr_resolve.c new file mode 100644 index 00000000..87734dea --- /dev/null +++ b/samples/socket-api/wasm-src/addr_resolve.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#ifdef __wasi__ +#include +#else +#include +#endif + +int +lookup_host(const char *host) +{ + struct addrinfo hints, *res, *result; + int errcode; + char addrstr[100]; + void *ptr; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + errcode = getaddrinfo(host, NULL, &hints, &result); + if (errcode != 0) { + perror("getaddrinfo"); + return -1; + } + + res = result; + + printf("Host: %s\n", host); + while (res) { + switch (res->ai_family) { + case AF_INET: + ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; + break; + case AF_INET6: + ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + break; + default: + printf("Unsupported address family: %d\n", res->ai_family); + continue; + } + inet_ntop(res->ai_family, ptr, addrstr, 100); + printf("IPv%d address: %s (%s)\n", res->ai_family == AF_INET6 ? 6 : 4, + addrstr, res->ai_socktype == SOCK_STREAM ? "TCP" : "UDP"); + res = res->ai_next; + } + + freeaddrinfo(result); + + return EXIT_SUCCESS; +} + +int +main(int argc, char *argv[]) +{ + if (argc < 2) { + printf("Usage: %s DOMAIN\n", argv[0]); + return EXIT_FAILURE; + } + + return lookup_host(argv[1]); +} diff --git a/samples/socket-api/wasm-src/socket_opts.c b/samples/socket-api/wasm-src/socket_opts.c new file mode 100644 index 00000000..3078c0b3 --- /dev/null +++ b/samples/socket-api/wasm-src/socket_opts.c @@ -0,0 +1,262 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#endif + +#define OPTION_ASSERT(A, B, OPTION) \ + if (A == B) { \ + printf("%s is expected\n", OPTION); \ + } \ + else { \ + printf("%s is unexpected\n", OPTION); \ + perror("assertion failed"); \ + return EXIT_FAILURE; \ + } + +struct timeval +to_timeval(time_t tv_sec, suseconds_t tv_usec) +{ + struct timeval tv = { tv_sec, tv_usec }; + return tv; +} + +int +set_and_get_bool_opt(int socket_fd, int level, int optname, int val) +{ + int bool_opt = val; + socklen_t opt_len = sizeof(bool_opt); + setsockopt(socket_fd, level, optname, &bool_opt, sizeof(bool_opt)); + bool_opt = !bool_opt; + getsockopt(socket_fd, level, optname, &bool_opt, &opt_len); + return bool_opt; +} + +int +main(int argc, char *argv[]) +{ + int tcp_socket_fd = 0; + int udp_socket_fd = 0; + int udp_ipv6_socket_fd = 0; + struct timeval tv; + socklen_t opt_len; + int buf_len; + int result; + struct linger linger_opt; + uint32_t time_s; + struct ip_mreq mcast; + struct ipv6_mreq mcast_ipv6; + unsigned char ttl; + + printf("[Client] Create TCP socket\n"); + tcp_socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (tcp_socket_fd == -1) { + perror("Create socket failed"); + return EXIT_FAILURE; + } + + printf("[Client] Create UDP socket\n"); + udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (udp_socket_fd == -1) { + perror("Create socket failed"); + return EXIT_FAILURE; + } + + printf("[Client] Create UDP IPv6 socket\n"); + udp_ipv6_socket_fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (udp_ipv6_socket_fd == -1) { + perror("Create socket failed"); + return EXIT_FAILURE; + } + + // SO_RCVTIMEO + tv = to_timeval(123, 1000); + setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + tv = to_timeval(0, 0); + opt_len = sizeof(tv); + getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &opt_len); + OPTION_ASSERT(tv.tv_sec, 123, "SO_RCVTIMEO tv_sec"); + OPTION_ASSERT(tv.tv_usec, 1000, "SO_RCVTIMEO tv_usec"); + + // SO_SNDTIMEO + tv = to_timeval(456, 2000); + setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + tv = to_timeval(0, 0); + opt_len = sizeof(tv); + getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &opt_len); + OPTION_ASSERT(tv.tv_sec, 456, "SO_SNDTIMEO tv_sec"); + OPTION_ASSERT(tv.tv_usec, 2000, "SO_SNDTIMEO tv_usec"); + + // SO_SNDBUF + buf_len = 8192; + setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, sizeof(buf_len)); + buf_len = 0; + opt_len = sizeof(buf_len); + getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, &opt_len); + OPTION_ASSERT(buf_len, 16384, "SO_SNDBUF buf_len"); + + // SO_RCVBUF + buf_len = 4096; + setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, sizeof(buf_len)); + buf_len = 0; + opt_len = sizeof(buf_len); + getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, &opt_len); + OPTION_ASSERT(buf_len, 8192, "SO_RCVBUF buf_len"); + + // SO_KEEPALIVE + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 1), 1, + "SO_KEEPALIVE enabled"); + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 0), 0, + "SO_KEEPALIVE disabled"); + + // SO_REUSEADDR + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 1), 1, + "SO_REUSEADDR enabled"); + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 0), 0, + "SO_REUSEADDR disabled"); + + // SO_REUSEPORT + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 1), 1, + "SO_REUSEPORT enabled"); + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 0), 0, + "SO_REUSEPORT disabled"); + + // SO_LINGER + linger_opt.l_onoff = 1; + linger_opt.l_linger = 10; + setsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, + sizeof(linger_opt)); + linger_opt.l_onoff = 0; + linger_opt.l_linger = 0; + opt_len = sizeof(linger_opt); + getsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, &opt_len); + OPTION_ASSERT(linger_opt.l_onoff, 1, "SO_LINGER l_onoff"); + OPTION_ASSERT(linger_opt.l_linger, 10, "SO_LINGER l_linger"); + + // SO_BROADCAST + OPTION_ASSERT( + set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 1), 1, + "SO_BROADCAST enabled"); + OPTION_ASSERT( + set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 0), 0, + "SO_BROADCAST disabled"); + + // TCP_KEEPIDLE + time_s = 16; + setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, + sizeof(time_s)); + time_s = 0; + opt_len = sizeof(time_s); + getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, &opt_len); + OPTION_ASSERT(time_s, 16, "TCP_KEEPIDLE"); + + // TCP_KEEPINTVL + time_s = 8; + setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, + sizeof(time_s)); + time_s = 0; + opt_len = sizeof(time_s); + getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, &opt_len); + OPTION_ASSERT(time_s, 8, "TCP_KEEPINTVL"); + + // TCP_FASTOPEN_CONNECT + OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, + TCP_FASTOPEN_CONNECT, 1), + 1, "TCP_FASTOPEN_CONNECT enabled"); + OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, + TCP_FASTOPEN_CONNECT, 0), + 0, "TCP_FASTOPEN_CONNECT disabled"); + + // TCP_NODELAY + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 1), 1, + "TCP_NODELAY enabled"); + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 0), 0, + "TCP_NODELAY disabled"); + + // TCP_QUICKACK + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 1), 1, + "TCP_QUICKACK enabled"); + OPTION_ASSERT( + set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 0), 0, + "TCP_QUICKACK disabled"); + + // IP_TTL + ttl = 8; + setsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + ttl = 0; + opt_len = sizeof(ttl); + getsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, &opt_len); + OPTION_ASSERT(ttl, 8, "IP_TTL"); + + // IPV6_V6ONLY + OPTION_ASSERT( + set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1), + 1, "IPV6_V6ONLY enabled"); + OPTION_ASSERT( + set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 0), + 0, "IPV6_V6ONLY disabled"); + + // IP_MULTICAST_LOOP + OPTION_ASSERT( + set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 1), + 1, "IP_MULTICAST_LOOP enabled"); + OPTION_ASSERT( + set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 0), + 0, "IP_MULTICAST_LOOP disabled"); + + // IP_ADD_MEMBERSHIP + mcast.imr_multiaddr.s_addr = 16777440; + mcast.imr_interface.s_addr = htonl(INADDR_ANY); + result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, + sizeof(mcast)); + OPTION_ASSERT(result, 0, "IP_ADD_MEMBERSHIP"); + + // IP_DROP_MEMBERSHIP + result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcast, + sizeof(mcast)); + OPTION_ASSERT(result, 0, "IP_DROP_MEMBERSHIP"); + + // IP_MULTICAST_TTL + ttl = 8; + setsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); + ttl = 0; + opt_len = sizeof(ttl); + getsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &opt_len); + OPTION_ASSERT(ttl, 8, "IP_MULTICAST_TTL"); + + // IPV6_MULTICAST_LOOP + OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, 1), + 1, "IPV6_MULTICAST_LOOP enabled"); + OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, 0), + 0, "IPV6_MULTICAST_LOOP disabled"); + + // IPV6_JOIN_GROUP + setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mcast_ipv6, + sizeof(mcast_ipv6)); + + // IPV6_LEAVE_GROUP + setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mcast_ipv6, + sizeof(mcast_ipv6)); + + printf("[Client] Close sockets\n"); + close(tcp_socket_fd); + close(udp_socket_fd); + return EXIT_SUCCESS; +} diff --git a/samples/socket-api/wasm-src/socket_utils.h b/samples/socket-api/wasm-src/socket_utils.h new file mode 100644 index 00000000..b69135b7 --- /dev/null +++ b/samples/socket-api/wasm-src/socket_utils.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef TCP_UTILS_H +#define TCP_UTILS_H + +#include +#include +#include + +int +sockaddr_to_string(struct sockaddr *addr, char *str, size_t len) +{ + uint16_t port; + char ip_string[64]; + void *addr_buf; + int ret; + + switch (addr->sa_family) { + case AF_INET: + { + struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; + port = addr_in->sin_port; + addr_buf = &addr_in->sin_addr; + break; + } + case AF_INET6: + { + struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr; + port = addr_in6->sin6_port; + addr_buf = &addr_in6->sin6_addr; + break; + } + default: + return -1; + } + + inet_ntop(addr->sa_family, addr_buf, ip_string, + sizeof(ip_string) / sizeof(ip_string[0])); + + ret = snprintf(str, len, "%s:%d", ip_string, ntohs(port)); + + return ret > 0 && (size_t)ret < len ? 0 : -1; +} + +#endif /* TCP_UTILS_H */ \ No newline at end of file diff --git a/samples/socket-api/wasm-src/tcp_client.c b/samples/socket-api/wasm-src/tcp_client.c index 4fcf8707..aad44948 100644 --- a/samples/socket-api/wasm-src/tcp_client.c +++ b/samples/socket-api/wasm-src/tcp_client.c @@ -2,6 +2,7 @@ * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#include "socket_utils.h" #include #include @@ -14,34 +15,77 @@ #include #endif +static void +init_sockaddr_inet(struct sockaddr_in *addr) +{ + /* 127.0.0.1:1234 */ + addr->sin_family = AF_INET; + addr->sin_port = htons(1234); + addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); +} + +static void +init_sockaddr_inet6(struct sockaddr_in6 *addr) +{ + /* [::1]:1234 */ + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(1234); + addr->sin6_addr = in6addr_loopback; +} + int main(int argc, char *argv[]) { - int socket_fd, ret, total_size = 0; + int socket_fd, ret, total_size = 0, af; char buffer[1024] = { 0 }; - struct sockaddr_in server_address = { 0 }; + char ip_string[64] = { 0 }; + socklen_t len; + struct sockaddr_storage server_address = { 0 }; + struct sockaddr_storage local_address = { 0 }; + + if (argc > 1 && strcmp(argv[1], "inet6") == 0) { + af = AF_INET6; + len = sizeof(struct sockaddr_in6); + init_sockaddr_inet6((struct sockaddr_in6 *)&server_address); + } + else { + af = AF_INET; + len = sizeof(struct sockaddr_in); + init_sockaddr_inet((struct sockaddr_in *)&server_address); + } printf("[Client] Create socket\n"); - socket_fd = socket(AF_INET, SOCK_STREAM, 0); + socket_fd = socket(af, 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); - printf("[Client] Connect socket\n"); - if (connect(socket_fd, (struct sockaddr *)&server_address, - sizeof(server_address)) - == -1) { + if (connect(socket_fd, (struct sockaddr *)&server_address, len) == -1) { perror("Connect failed"); close(socket_fd); return EXIT_FAILURE; } + len = sizeof(local_address); + ret = getsockname(socket_fd, (struct sockaddr *)&local_address, &len); + if (ret == -1) { + perror("Failed to retrieve socket address"); + close(socket_fd); + return EXIT_FAILURE; + } + + if (sockaddr_to_string((struct sockaddr *)&local_address, ip_string, + sizeof(ip_string) / sizeof(ip_string[0])) + != 0) { + printf("[Client] failed to parse local address\n"); + close(socket_fd); + return EXIT_FAILURE; + } + + printf("[Client] Local address is: %s\n", ip_string); + printf("[Client] Client receive\n"); while (1) { ret = recv(socket_fd, buffer + total_size, sizeof(buffer) - total_size, diff --git a/samples/socket-api/wasm-src/tcp_server.c b/samples/socket-api/wasm-src/tcp_server.c index 4b8b4362..2798dc25 100644 --- a/samples/socket-api/wasm-src/tcp_server.c +++ b/samples/socket-api/wasm-src/tcp_server.c @@ -2,6 +2,8 @@ * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#include "socket_utils.h" + #include #include #include @@ -41,29 +43,53 @@ run(void *arg) return NULL; } +static void +init_sockaddr_inet(struct sockaddr_in *addr) +{ + /* 0.0.0.0:1234 */ + addr->sin_family = AF_INET; + addr->sin_port = htons(1234); + addr->sin_addr.s_addr = htonl(INADDR_ANY); +} + +static void +init_sockaddr_inet6(struct sockaddr_in6 *addr) +{ + /* [::]:1234 */ + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(1234); + addr->sin6_addr = in6addr_any; +} + int main(int argc, char *argv[]) { - int socket_fd = -1, addrlen = 0; - struct sockaddr_in addr = { 0 }; + int socket_fd = -1, addrlen = 0, af; + struct sockaddr_storage addr = { 0 }; unsigned connections = 0; pthread_t workers[WORKER_NUM] = { 0 }; int client_sock_fds[WORKER_NUM] = { 0 }; + char ip_string[64]; + + if (argc > 1 && strcmp(argv[1], "inet6") == 0) { + af = AF_INET6; + addrlen = sizeof(struct sockaddr_in6); + init_sockaddr_inet6((struct sockaddr_in6 *)&addr); + } + else { + af = AF_INET; + addrlen = sizeof(struct sockaddr_in6); + init_sockaddr_inet((struct sockaddr_in *)&addr); + } printf("[Server] Create socket\n"); - socket_fd = socket(AF_INET, SOCK_STREAM, 0); + socket_fd = socket(af, 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); - printf("[Server] Bind socket\n"); - addrlen = sizeof(addr); if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) { perror("Bind failed"); goto fail; @@ -77,6 +103,7 @@ main(int argc, char *argv[]) printf("[Server] Wait for clients to connect ..\n"); while (connections < WORKER_NUM) { + addrlen = sizeof(struct sockaddr); client_sock_fds[connections] = accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen); if (client_sock_fds[connections] < 0) { @@ -84,7 +111,14 @@ main(int argc, char *argv[]) break; } - printf("[Server] Client connected\n"); + if (sockaddr_to_string((struct sockaddr *)&addr, ip_string, + sizeof(ip_string) / sizeof(ip_string[0])) + != 0) { + printf("[Server] failed to parse client address\n"); + goto fail; + } + + printf("[Server] Client connected (%s)\n", ip_string); if (pthread_create(&workers[connections], NULL, run, &client_sock_fds[connections])) { perror("Create a worker thread failed"); diff --git a/samples/socket-api/wasm-src/udp_client.c b/samples/socket-api/wasm-src/udp_client.c new file mode 100644 index 00000000..96d9a2b8 --- /dev/null +++ b/samples/socket-api/wasm-src/udp_client.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#endif + +static void +init_sockaddr_inet(struct sockaddr_in *addr) +{ + /* 127.0.0.1:1234 */ + addr->sin_family = AF_INET; + addr->sin_port = htons(1234); + addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); +} + +static void +init_sockaddr_inet6(struct sockaddr_in6 *addr) +{ + /* [::1]:1234 */ + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(1234); + addr->sin6_addr = in6addr_loopback; +} + +int +main(int argc, char *argv[]) +{ + int socket_fd, ret, af; + char buffer[1024] = { 0 }; + socklen_t serverlen; + struct sockaddr_storage server_address = { 0 }; + const char *message = "Hello from client"; + + if (argc > 1 && strcmp(argv[1], "inet6") == 0) { + af = AF_INET6; + init_sockaddr_inet6((struct sockaddr_in6 *)&server_address); + serverlen = sizeof(struct sockaddr_in6); + } + else { + af = AF_INET; + init_sockaddr_inet((struct sockaddr_in *)&server_address); + serverlen = sizeof(struct sockaddr_in); + } + + printf("[Client] Create socket\n"); + socket_fd = socket(af, SOCK_DGRAM, 0); + if (socket_fd == -1) { + perror("Create socket failed"); + return EXIT_FAILURE; + } + + printf("[Client] Client send\n"); + ret = sendto(socket_fd, message, strlen(message), 0, + (struct sockaddr *)&server_address, serverlen); + if (ret < 0) { + close(socket_fd); + perror("Send failed"); + return EXIT_FAILURE; + } + + printf("[Client] Client receive\n"); + serverlen = sizeof(server_address); + ret = recvfrom(socket_fd, buffer, sizeof(buffer), 0, + (struct sockaddr *)&server_address, &serverlen); + + if (ret > 0) { + printf("[Client] Buffer recieved: %s\n", buffer); + } + + close(socket_fd); + printf("[Client] BYE \n"); + return EXIT_SUCCESS; +} diff --git a/samples/socket-api/wasm-src/udp_server.c b/samples/socket-api/wasm-src/udp_server.c new file mode 100644 index 00000000..1e24dd2f --- /dev/null +++ b/samples/socket-api/wasm-src/udp_server.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "socket_utils.h" + +#include +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#endif + +#define MAX_CONNECTIONS_COUNT 5 + +static void +init_sockaddr_inet(struct sockaddr_in *addr) +{ + /* 0.0.0.0:1234 */ + addr->sin_family = AF_INET; + addr->sin_port = htons(1234); + addr->sin_addr.s_addr = htonl(INADDR_ANY); +} + +static void +init_sockaddr_inet6(struct sockaddr_in6 *addr) +{ + /* [::]:1234 */ + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(1234); + addr->sin6_addr = in6addr_any; +} + +int +main(int argc, char *argv[]) +{ + int socket_fd = -1, af; + socklen_t addrlen = 0; + struct sockaddr_storage addr = { 0 }; + char *reply_message = "Hello from server"; + unsigned connections = 0; + char ip_string[64]; + char buffer[1024]; + + if (argc > 1 && strcmp(argv[1], "inet6") == 0) { + af = AF_INET6; + addrlen = sizeof(struct sockaddr_in6); + init_sockaddr_inet6((struct sockaddr_in6 *)&addr); + } + else { + af = AF_INET; + addrlen = sizeof(struct sockaddr_in); + init_sockaddr_inet((struct sockaddr_in *)&addr); + } + + printf("[Server] Create socket\n"); + socket_fd = socket(af, SOCK_DGRAM, 0); + if (socket_fd < 0) { + perror("Create socket failed"); + goto fail; + } + + printf("[Server] Bind socket\n"); + if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) { + perror("Bind failed"); + goto fail; + } + + printf("[Server] Wait for clients to connect ..\n"); + while (connections < MAX_CONNECTIONS_COUNT) { + addrlen = sizeof(addr); + int ret = recvfrom(socket_fd, buffer, sizeof(buffer), 0, + (struct sockaddr *)&addr, &addrlen); + if (ret < 0) { + perror("Read failed"); + goto fail; + } + + if (sockaddr_to_string((struct sockaddr *)&addr, ip_string, + sizeof(ip_string) / sizeof(ip_string[0])) + != 0) { + printf("[Server] failed to parse client address\n"); + goto fail; + } + + printf("[Server] received %d bytes from %s: %s\n", ret, ip_string, + buffer); + + if (sendto(socket_fd, reply_message, strlen(reply_message), 0, + (struct sockaddr *)&addr, addrlen) + < 0) { + perror("Send failed"); + break; + } + + connections++; + } + + if (connections == MAX_CONNECTIONS_COUNT) { + printf("[Server] Achieve maximum amount of connections\n"); + } + + printf("[Server] Shuting down ..\n"); + shutdown(socket_fd, SHUT_RDWR); + close(socket_fd); + 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; +} From 1ff04a912513f23c7f7ec977ca6f07f02c90f7a9 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 23 Sep 2022 09:31:44 +0800 Subject: [PATCH 15/29] Fix issue in wasm/aot enlarge memory (#1512) Memory num_bytes_per_page was incorrectly set in memory enlarging for shared memory, we fix it. And don't set memory_data_size again for shared memory. --- core/iwasm/aot/aot_runtime.c | 6 ++++-- core/iwasm/interpreter/wasm_runtime.c | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 0fd805f9..6213bce1 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -2097,10 +2097,12 @@ aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) #if WASM_ENABLE_SHARED_MEMORY != 0 if (memory->is_shared) { - memory->num_bytes_per_page = UINT32_MAX; + memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = total_page_count; memory->max_page_count = max_page_count; - memory->memory_data_size = (uint32)total_size_new; + /* No need to update memory->memory_data_size as it is + initialized with the maximum memory data size for + shared memory */ return true; } #endif diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 669852a5..db8eccb7 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -2507,9 +2507,12 @@ wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) #if WASM_ENABLE_SHARED_MEMORY != 0 if (memory->is_shared) { - memory->num_bytes_per_page = UINT32_MAX; + memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = total_page_count; memory->max_page_count = max_page_count; + /* No need to update memory->memory_data_size as it is + initialized with the maximum memory data size for + shared memory */ return true; } #endif From 3693cbe54db6cee3fedccd0d5666ffa430bcfb0b Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Sep 2022 11:34:47 +0900 Subject: [PATCH 16/29] Suppress hadolint warnings for pinning versions part (#1511) Related to https://github.com/bytecodealliance/wasm-micro-runtime/issues/1418. Suppress hadolint warnings for pinning version. This is because these warnings are for reproducible builds. But for development and CIs, ordinary case developers have to use the latest packages. --- .devcontainer/Dockerfile | 8 ++++++-- test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile | 2 +- test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile | 1 + test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile | 2 ++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 89249f1b..5ddba8f3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -9,6 +9,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT} ARG DEBIAN_FRONTEND=noninteractive ENV TZ=Asian/Shanghai +# hadolint ignore=DL3008 RUN apt-get update \ && apt-get install -y apt-transport-https apt-utils build-essential \ ca-certificates curl g++-multilib git gnupg \ @@ -17,11 +18,12 @@ RUN apt-get update \ software-properties-common tree tzdata \ unzip valgrind vim wget zip --no-install-recommends \ && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* # # CMAKE (https://apt.kitware.com/) SHELL ["/bin/bash", "-o", "pipefail", "-c"] +# hadolint ignore=DL3008 RUN wget --progress=dot:giga -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg > /dev/null \ && echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null \ && apt-get update \ @@ -84,13 +86,15 @@ RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \ # # Install pip +# hadolint ignore=DL3008 RUN apt-get update \ && apt-get install -y --reinstall python3-venv python3-pip --no-install-recommends \ && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* # # Install required python packages +# hadolint ignore=DL3013 RUN python3 -m pip install --no-cache-dir --upgrade pip \ && pip3 install --no-cache-dir --user black nose pycparser pylint diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile b/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile index 5430ab8d..a796725f 100644 --- a/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile @@ -3,7 +3,7 @@ FROM python:3.5 WORKDIR /app COPY . /app +# hadolint ignore=DL3013 RUN pip install django --no-cache-dir ENTRYPOINT ["python", "manage.py", "runserver", "0.0.0.0:80"] - diff --git a/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile b/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile index 2c4cb5b5..20e0be55 100644 --- a/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile +++ b/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile @@ -8,6 +8,7 @@ WORKDIR /root/ COPY resource /root/ ## - download cmake with wget and set up +# hadolint ignore=DL3008 RUN wget --progress=dot:giga https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-linux-x86_64.tar.gz \ && tar -zxvf cmake-3.21.1-linux-x86_64.tar.gz \ && rm -f cmake-3.21.1-linux-x86_64.tar.gz \ diff --git a/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile b/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile index 739b0d14..f96a2261 100644 --- a/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile +++ b/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile @@ -10,6 +10,7 @@ WORKDIR /root/ COPY resource /root/ ## - download cmake with wget and set up +# hadolint ignore=DL3008 RUN wget --progress=dot:giga https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1-linux-x86_64.tar.gz \ && tar -zxvf cmake-3.21.1-linux-x86_64.tar.gz \ && rm -f cmake-3.21.1-linux-x86_64.tar.gz \ @@ -66,6 +67,7 @@ COPY --from=BASE /root/build_wasm.sh ${HOME_DIR} RUN ln -s /opt/cmake/bin/cmake /usr/bin/cmake \ && ln -s ${HOME_DIR}/wamrc /usr/bin/wamrc +# hadolint ignore=DL3008 RUN apt-get update && apt-get install -y make --no-install-recommends \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* From 3d56c8133c8e22976572a03be4cd6a9946a1edd4 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Mon, 26 Sep 2022 21:06:14 +0900 Subject: [PATCH 17/29] Fix NuttX build error after dev/socket was merged (#1517) --- core/shared/platform/common/posix/posix_socket.c | 14 ++++++++++++-- core/shared/platform/nuttx/platform_internal.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/core/shared/platform/common/posix/posix_socket.c b/core/shared/platform/common/posix/posix_socket.c index adb7b11d..c1c72008 100644 --- a/core/shared/platform/common/posix/posix_socket.c +++ b/core/shared/platform/common/posix/posix_socket.c @@ -426,7 +426,7 @@ os_socket_getbooloption(bh_socket_t socket, int level, int optname, assert(is_enabled); int optval; - int optval_size = sizeof(optval); + socklen_t optval_size = sizeof(optval); if (getsockopt(socket, level, optname, &optval, &optval_size) != 0) { return BHT_ERROR; } @@ -523,15 +523,25 @@ os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled) int os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled) { +#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ return os_socket_setbooloption(socket, SOL_SOCKET, SO_REUSEPORT, is_enabled); +#else + errno = ENOTSUP; + return BHT_ERROR; +#endif /* defined(SO_REUSEPORT) */ } int os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled) { +#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ return os_socket_getbooloption(socket, SOL_SOCKET, SO_REUSEPORT, is_enabled); +#else + errno = ENOTSUP; + return BHT_ERROR; +#endif /* defined(SO_REUSEPORT) */ } int @@ -967,4 +977,4 @@ os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len, sockaddr); -} \ No newline at end of file +} diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h index 637fa21f..41e20858 100644 --- a/core/shared/platform/nuttx/platform_internal.h +++ b/core/shared/platform/nuttx/platform_internal.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include From 8436e88a0718af8614714bacfdff4cf45958def5 Mon Sep 17 00:00:00 2001 From: dongsheng28849455 <68947925+dongsheng28849455@users.noreply.github.com> Date: Tue, 27 Sep 2022 09:00:38 +0800 Subject: [PATCH 18/29] Fix link error for ESP-IDF 4.4.2 (#1520) Fix the issue reported by #1484: Platform ESP-IDF broken for WAMR 1.0.0 with ESP-IDF 4.4.2 Let the dummy ftruncate only work with ESP-IDF earlier than 4.4.2 --- core/shared/platform/esp-idf/espidf_platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/shared/platform/esp-idf/espidf_platform.c b/core/shared/platform/esp-idf/espidf_platform.c index 896190db..d05b19f5 100644 --- a/core/shared/platform/esp-idf/espidf_platform.c +++ b/core/shared/platform/esp-idf/espidf_platform.c @@ -228,12 +228,14 @@ fdopendir(int fd) return NULL; } +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 2) int ftruncate(int fd, off_t length) { errno = ENOSYS; return -1; } +#endif int futimens(int fd, const struct timespec times[2]) From fa736d1ee942690ff458863ec090fcbc31d4962a Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 27 Sep 2022 09:57:08 +0200 Subject: [PATCH 19/29] Fix syntax errors and undefined names in Python code (#1515) --- .../wasm_django/devices/views.py | 6 ++--- test-tools/component-test/framework/engine.py | 3 ++- .../component-test/framework/framework.py | 25 ++++++++++--------- .../component-test/framework/test_api.py | 9 ++++--- .../component-test/framework/test_utils.py | 9 ++++--- test-tools/component-test/start.py | 23 +++++++++-------- .../spec-test-script/runtest.py | 14 ++++++++--- 7 files changed, 50 insertions(+), 39 deletions(-) diff --git a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py index cc11a27a..1afa1f95 100755 --- a/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py +++ b/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py @@ -268,6 +268,6 @@ def removeapps(req): return render(req, 'appstore.html', {'alist': json.dumps(avaliable_list),'flist': json.dumps(user_file_list)}) # Test -if __name__ == "__main__": - print(device_list[0]['IP']) - print(device['IP']) +# if __name__ == "__main__": +# print(device_list[0]['IP']) +# print(device['IP']) diff --git a/test-tools/component-test/framework/engine.py b/test-tools/component-test/framework/engine.py index 48911d19..6c68a1eb 100644 --- a/test-tools/component-test/framework/engine.py +++ b/test-tools/component-test/framework/engine.py @@ -1,3 +1,4 @@ +from __future__ import print_function # # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -28,7 +29,7 @@ def read_cases_from_file(file_path): content = f.readlines() content = [x.strip() for x in content] - print content + print(content) if len(content) == 0: return False, None diff --git a/test-tools/component-test/framework/framework.py b/test-tools/component-test/framework/framework.py index 78e187fe..99f0b077 100644 --- a/test-tools/component-test/framework/framework.py +++ b/test-tools/component-test/framework/framework.py @@ -1,3 +1,4 @@ +from __future__ import print_function # # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -66,7 +67,7 @@ class CTestFramework(object): api_set_root_path(path) - print "root_path is " + self.root_path + print("root_path is " + self.root_path) def gen_execution_stats(self): return '\nTest Execution Summary: ' \ @@ -103,7 +104,7 @@ class CTestFramework(object): module_name = 'suites.' + suite + ".cases." + case + ".case" try: module = my_import(module_name) - except Exception, e: + except Exception as e: report_fail("load case fail: " + str(e)) api_log_error("load case fail: " + str(e)) self.load_fails = self.load_fails +1 @@ -112,7 +113,7 @@ class CTestFramework(object): try: case = module.CTestCase(suite_instance) - except Exception, e: + except Exception as e: report_fail("initialize case fail: " + str(e)) api_log_error("initialize case fail: " + str(e)) self.load_fails = self.load_fails +1 @@ -122,7 +123,7 @@ class CTestFramework(object): try: case_description = case.on_get_case_description() result, message = case.on_setup_case() - except Exception, e: + except Exception as e: result = False message = str(e); if not result: @@ -134,7 +135,7 @@ class CTestFramework(object): # call the case execution callaback try: result, message = case.on_run_case() - except Exception, e: + except Exception as e: result = False message = str(e); if not result: @@ -148,7 +149,7 @@ class CTestFramework(object): # call the case cleanup callback try: clean_result, message = case.on_cleanup_case() - except Exception, e: + except Exception as e: clean_result = False message = str(e) @@ -166,7 +167,7 @@ class CTestFramework(object): module_name = 'suites.' + suite + ".suite_setup" try: module = my_import(module_name) - except Exception, e: + except Exception as e: report_fail("load suite [" + suite +"] fail: " + str(e)) self.load_fails = self.load_fails +1 return False @@ -174,7 +175,7 @@ class CTestFramework(object): try: suite_instance = module.CTestSuite(suite, \ self.root_path + '/suites/' + suite, running_folder) - except Exception, e: + except Exception as e: report_fail("initialize suite fail: " + str(e)) self.load_fails = self.load_fails +1 return False @@ -187,7 +188,7 @@ class CTestFramework(object): try: result, message = suite_instance.on_suite_setup() - except Exception, e: + except Exception as e: result = False message = str(e); if not result: @@ -213,7 +214,7 @@ class CTestFramework(object): self.running_suite = '' try: result, message = suite_instance.on_suite_cleanup() - except Exception, e: + except Exception as e: result = False message = str(e); if not result: @@ -224,7 +225,7 @@ class CTestFramework(object): def start_run(self): if self.target_suites is None: - print "\n\nstart run: no target suites, exit.." + print("\n\nstart run: no target suites, exit..") return cur_time = time.localtime() @@ -268,7 +269,7 @@ class CTestFramework(object): self.report.write(summary); self.report.flush() self.report.close() - print summary + print(summary) def report_fail(message, case_description=''): diff --git a/test-tools/component-test/framework/test_api.py b/test-tools/component-test/framework/test_api.py index ed9391e2..82a7e6dd 100644 --- a/test-tools/component-test/framework/test_api.py +++ b/test-tools/component-test/framework/test_api.py @@ -1,3 +1,4 @@ +from __future__ import print_function # # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -12,7 +13,7 @@ logger = None def api_init_log(log_path): global logger - print "api_init_log: " + log_path + print("api_init_log: " + log_path) logger = logging.getLogger(__name__) logger.setLevel(level = logging.INFO) @@ -32,7 +33,7 @@ def api_init_log(log_path): def api_log(message): global logger if logger is None: - print message + print(message) else: logger.info (message) return @@ -40,7 +41,7 @@ def api_log(message): def api_log_error(message): global logger if logger is None: - print message + print(message) else: logger.error (message) return @@ -48,7 +49,7 @@ def api_log_error(message): def api_logv(message): global logger if logger is None: - print message + print(message) else: logger.info(message) return diff --git a/test-tools/component-test/framework/test_utils.py b/test-tools/component-test/framework/test_utils.py index 1b8bbd01..e3eb645a 100644 --- a/test-tools/component-test/framework/test_utils.py +++ b/test-tools/component-test/framework/test_utils.py @@ -1,3 +1,4 @@ +from __future__ import print_function # # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -52,7 +53,7 @@ def t_process_exists(proc, kill = 0): if kill == 0: return True else: - print "kill [" + proc + "], pid=" + str(pid) + print("kill [" + proc + "], pid=" + str(pid)) os.kill((pid), 9) ret = True return ret @@ -60,11 +61,11 @@ def t_process_exists(proc, kill = 0): def t_copy_files(source_dir, pattern, dest_dir): files = os.listdir(source_dir) for file in files: - if file is '/' or file is '.' or file is '..': + if file in ('/', '.', '..'): continue - if pattern == '*' or pattern is '' or files.endswith(pattern): - shutil.copy(source_dir+"/"+ file,dest_dir) + if pattern in ('*', '') or files.endswith(pattern): + shutil.copy(source_dir+"/"+ file, dest_dir) diff --git a/test-tools/component-test/start.py b/test-tools/component-test/start.py index 062ec2e4..2cbc4fe6 100755 --- a/test-tools/component-test/start.py +++ b/test-tools/component-test/start.py @@ -10,6 +10,7 @@ It is the entrance of the iagent test framework. """ +from __future__ import print_function import argparse import datetime @@ -84,9 +85,9 @@ if __name__ == "__main__": help = 'rebuild all test binaries') args = parser.parse_args() - print "------------------------------------------------------------" - print "parsing arguments ... ..." - print args + print("------------------------------------------------------------") + print("parsing arguments ... ...") + print(args) ''' logger = logging.getLogger('coapthon.server.coap') @@ -95,8 +96,8 @@ if __name__ == "__main__": console.setLevel(logging.DEBUG) logger.addHandler(console) ''' - print "------------------------------------------------------------" - print "preparing wamr binary and test tools ... ..." + print("------------------------------------------------------------") + print("preparing wamr binary and test tools ... ...") os.system("cd ../../samples/simple/ && bash build.sh -p host-interp") Register_signal_handler() @@ -124,9 +125,9 @@ if __name__ == "__main__": if binary_path is None: binary_path = os.path.abspath(dirname + '/../..') - print "checking execution binary path: " + binary_path + print("checking execution binary path: " + binary_path) if not os.path.exists(binary_path): - print "The execution binary path was not available. quit..." + print("The execution binary path was not available. quit...") os._exit(0) api_set_value('binary_path', binary_path) @@ -138,11 +139,11 @@ if __name__ == "__main__": framework.target_cases = cases_list framework.start_run() - print "\n\n------------------------------------------------------------" - print "The run folder is [" + framework.running_folder +"]" - print "that's all. bye" + print("\n\n------------------------------------------------------------") + print("The run folder is [" + framework.running_folder +"]") + print("that's all. bye") - print "kill to quit.." + print("kill to quit..") t_kill_process_by_name("start.py") sys.exit(0) diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index 9053a720..ef4eb162 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -2,6 +2,7 @@ from __future__ import print_function import os, sys, re +from pickletools import long1 import argparse, time import signal, atexit, tempfile, subprocess @@ -17,7 +18,12 @@ import struct import math import traceback -IS_PY_3 = sys.version_info[0] == 3 +try: + long + IS_PY_3 = False +except NameError: + long = int + IS_PY_3 = True test_aot = False # "x86_64", "i386", "aarch64", "armv7" or "thumbv7" @@ -312,7 +318,7 @@ def get_module_exp_from_assert(string): def string_to_unsigned(number_in_string, lane_type): if not lane_type in ['i8x16', 'i16x8', 'i32x4', 'i64x2']: - raise Exception("invalid value {} and type {} and lane_type {}".format(numbers, type, lane_type)) + raise Exception("invalid value {} and type {} and lane_type {}".format(number_in_string, type, lane_type)) number = int(number_in_string, 16) if '0x' in number_in_string else int(number_in_string) @@ -896,7 +902,7 @@ def skip_test(form, skip_list): def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): log("Writing WAST module to '%s'" % wast_tempfile) - file(wast_tempfile, 'w').write(form) + open(wast_tempfile, 'w').write(form) log("Compiling WASM to '%s'" % wasm_tempfile) # default arguments @@ -1122,7 +1128,7 @@ if __name__ == "__main__": # workaround: spec test changes error message to "malformed" while iwasm still use "invalid" error_msg = m.group(2).replace("malformed", "invalid") log("Testing(malformed)") - f = file(wasm_tempfile, 'w') + f = open(wasm_tempfile, 'w') s = m.group(1) while s: res = re.match("[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL) From dfd16f8e4f82de64bdc6259f87fb7d69684a9ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A4mes=20M=C3=A9n=C3=A9trey?= Date: Wed, 28 Sep 2022 07:09:58 +0200 Subject: [PATCH 20/29] linux-sgx: Implement SGX IPFS as POSIX backend for file interaction (#1489) This PR integrates an Intel SGX feature called Intel Protection File System Library (IPFS) into the runtime to create, operate and delete files inside the enclave, while guaranteeing the confidentiality and integrity of the data persisted. IPFS can be referred to here: https://www.intel.com/content/www/us/en/developer/articles/technical/overview-of-intel-protected-file-system-library-using-software-guard-extensions.html Introduce a cmake variable `WAMR_BUILD_SGX_IPFS`, when enabled, the files interaction API of WASI will leverage IPFS, instead of the regular POSIX OCALLs. The implementation has been written with light changes to sgx platform layer, so all the security aspects WAMR relies on are conserved. In addition to this integration, the following changes have been made: - The CI workflow has been adapted to test the compilation of the runtime and sample with the flag `WAMR_BUILD_SGX_IPFS` set to true - Introduction of a new sample that demonstrates the interaction of the files (called `file`), - Documentation of this new feature --- .../compilation_on_android_ubuntu.yml | 9 + .github/workflows/compilation_on_macos.yml | 9 + .github/workflows/compilation_on_sgx.yml | 10 + README.md | 1 + build-scripts/config_common.cmake | 4 + core/config.h | 4 + core/shared/platform/linux-sgx/sgx_file.c | 64 +++ core/shared/platform/linux-sgx/sgx_ipfs.c | 460 ++++++++++++++++++ core/shared/platform/linux-sgx/sgx_ipfs.h | 61 +++ core/shared/platform/linux-sgx/sgx_platform.c | 18 +- doc/linux_sgx.md | 51 ++ .../platforms/linux-sgx/CMakeLists.txt | 25 + .../enclave-sample/Enclave/Enclave.edl | 4 + .../linux-sgx/enclave-sample/Makefile | 12 +- samples/file/CMakeLists.txt | 9 + samples/file/README.md | 112 +++++ samples/file/src/CMakeLists.txt | 87 ++++ samples/file/src/main.c | 117 +++++ samples/file/wasm-app/CMakeLists.txt | 26 + samples/file/wasm-app/main.c | 132 +++++ 20 files changed, 1211 insertions(+), 4 deletions(-) create mode 100644 core/shared/platform/linux-sgx/sgx_ipfs.c create mode 100644 core/shared/platform/linux-sgx/sgx_ipfs.h create mode 100644 samples/file/CMakeLists.txt create mode 100644 samples/file/README.md create mode 100644 samples/file/src/CMakeLists.txt create mode 100644 samples/file/src/main.c create mode 100644 samples/file/wasm-app/CMakeLists.txt create mode 100644 samples/file/wasm-app/main.c diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 8a79e7ad..97021f17 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -413,6 +413,15 @@ jobs: ./build.sh ./run.sh + - name: Build Sample [file] + if: ${{ matrix.light == 'green' }} + run: | + cd samples/file + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./src/iwasm -f wasm-app/file.wasm -d . + - name: Build Sample [multi-thread] if: ${{ matrix.light == 'green' }} run: | diff --git a/.github/workflows/compilation_on_macos.yml b/.github/workflows/compilation_on_macos.yml index 9afbb844..ceacacd8 100644 --- a/.github/workflows/compilation_on_macos.yml +++ b/.github/workflows/compilation_on_macos.yml @@ -356,6 +356,15 @@ jobs: ./build.sh ./run.sh + - name: Build Sample [file] + if: ${{ matrix.light == 'green' }} + run: | + cd samples/file + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./src/iwasm -f wasm-app/file.wasm -d . + - name: Build Sample [multi-thread] if: ${{ matrix.light == 'green' }} run: | diff --git a/.github/workflows/compilation_on_sgx.yml b/.github/workflows/compilation_on_sgx.yml index f21b618c..98ebb457 100644 --- a/.github/workflows/compilation_on_sgx.yml +++ b/.github/workflows/compilation_on_sgx.yml @@ -140,6 +140,7 @@ jobs: # "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_TAIL_CALL=1", "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_SGX_IPFS=1", ] os: [ubuntu-20.04] platform: [linux-sgx] @@ -363,6 +364,15 @@ jobs: ./build.sh ./run.sh + - name: Build Sample [file] + if: ${{ matrix.light == 'green' }} + run: | + cd samples/file + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./src/iwasm -f wasm-app/file.wasm -d . + - name: Build Sample [multi-thread] if: ${{ matrix.light == 'green' }} run: | diff --git a/README.md b/README.md index 02f7ea3c..84bee711 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a - [**basic**](./samples/basic): Demonstrating how to use runtime exposed API's to call WASM functions, how to register native functions and call them, and how to call WASM function from native function. - **[simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default. +- **[file](./samples/file/README.md)**: Demonstrating the supported file interaction API of WASI. This sample can also demonstrate the SGX IPFS (Intel Protected File System), enabling an enclave to seal and unseal data at rest. - **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LVGL](https://github.com/lvgl/lvgl) 2D user graphic library and the UI application are built into WASM application. It uses **WASI libc** and executes apps in **AOT mode** by default. - **[gui](./samples/gui/README.md)**: Move the [LVGL](https://github.com/lvgl/lvgl) library into the runtime and define a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. - **[multi-thread](./samples/multi-thread/)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently, and uses mutex/cond by calling pthread related API's. diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 8d99b93a..21ddc501 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -287,3 +287,7 @@ if (WAMR_BUILD_STACK_GUARD_SIZE GREATER 0) add_definitions (-DWASM_STACK_GUARD_SIZE=${WAMR_BUILD_STACK_GUARD_SIZE}) message (" Custom stack guard size: " ${WAMR_BUILD_STACK_GUARD_SIZE}) endif () +if (WAMR_BUILD_SGX_IPFS EQUAL 1) + add_definitions (-DWASM_ENABLE_SGX_IPFS=1) + message (" SGX IPFS enabled") +endif () diff --git a/core/config.h b/core/config.h index 728bdc7e..024913b7 100644 --- a/core/config.h +++ b/core/config.h @@ -407,4 +407,8 @@ #define WASM_ENABLE_REF_TYPES 0 #endif +#ifndef WASM_ENABLE_SGX_IPFS +#define WASM_ENABLE_SGX_IPFS 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/shared/platform/linux-sgx/sgx_file.c b/core/shared/platform/linux-sgx/sgx_file.c index f71249fc..772a8087 100644 --- a/core/shared/platform/linux-sgx/sgx_file.c +++ b/core/shared/platform/linux-sgx/sgx_file.c @@ -7,6 +7,10 @@ #include "sgx_error.h" #include "sgx_file.h" +#if WASM_ENABLE_SGX_IPFS != 0 +#include "sgx_ipfs.h" +#endif + #ifndef SGX_DISABLE_WASI #define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__) @@ -184,6 +188,22 @@ openat(int dirfd, const char *pathname, int flags, ...) if (fd == -1) errno = get_errno(); + +#if WASM_ENABLE_SGX_IPFS != 0 + // When WAMR uses Intel SGX IPFS to enabled, it opens a second + // file descriptor to interact with the secure file. + // The first file descriptor opened earlier is used to interact + // with the metadata of the file (e.g., time, flags, etc.). + int ret; + void *file_ptr = ipfs_fopen(fd, pathname, flags); + if (file_ptr == NULL) { + if (ocall_close(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return -1; + } +#endif + return fd; } @@ -192,6 +212,13 @@ close(int fd) { int ret; +#if WASM_ENABLE_SGX_IPFS != 0 + // Close the IPFS file pointer in addition of the file descriptor + ret = ipfs_close(fd); + if (ret == -1) + errno = get_errno(); +#endif + if (ocall_close(&ret, fd) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); return -1; @@ -345,6 +372,12 @@ readv_internal(int fd, const struct iovec *iov, int iovcnt, bool has_offset, if (total_size >= UINT32_MAX) return -1; +#if WASM_ENABLE_SGX_IPFS != 0 + if (fd > 2) { + return ipfs_read(fd, iov, iovcnt, has_offset, offset); + } +#endif + iov1 = BH_MALLOC((uint32)total_size); if (iov1 == NULL) @@ -410,6 +443,12 @@ writev_internal(int fd, const struct iovec *iov, int iovcnt, bool has_offset, if (total_size >= UINT32_MAX) return -1; +#if WASM_ENABLE_SGX_IPFS != 0 + if (fd > 2) { + return ipfs_write(fd, iov, iovcnt, has_offset, offset); + } +#endif + iov1 = BH_MALLOC((uint32)total_size); if (iov1 == NULL) @@ -468,12 +507,18 @@ off_t lseek(int fd, off_t offset, int whence) { off_t ret; + +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_lseek(fd, offset, whence); +#else if (ocall_lseek(&ret, fd, (long)offset, whence) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); return -1; } if (ret == -1) errno = get_errno(); +#endif + return ret; } @@ -482,12 +527,17 @@ ftruncate(int fd, off_t length) { int ret; +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_ftruncate(fd, length); +#else if (ocall_ftruncate(&ret, fd, length) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); return -1; } if (ret == -1) errno = get_errno(); +#endif + return ret; } @@ -554,12 +604,17 @@ fsync(int fd) { int ret; +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_fflush(fd); +#else if (ocall_fsync(&ret, fd) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); return -1; } if (ret == -1) errno = get_errno(); +#endif + return ret; } @@ -568,12 +623,17 @@ fdatasync(int fd) { int ret; +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_fflush(fd); +#else if (ocall_fdatasync(&ret, fd) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); return -1; } if (ret == -1) errno = get_errno(); +#endif + return ret; } @@ -801,10 +861,14 @@ posix_fallocate(int fd, off_t offset, off_t len) { int ret; +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_posix_fallocate(fd, offset, len); +#else if (ocall_posix_fallocate(&ret, fd, offset, len) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); return -1; } +#endif return ret; } diff --git a/core/shared/platform/linux-sgx/sgx_ipfs.c b/core/shared/platform/linux-sgx/sgx_ipfs.c new file mode 100644 index 00000000..76750946 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_ipfs.c @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#if WASM_ENABLE_SGX_IPFS != 0 + +#include "ssp_config.h" +#include "bh_platform.h" +#include "sgx_ipfs.h" + +#include + +#include "sgx_tprotected_fs.h" + +#define SGX_ERROR_FILE_LOWEST_ERROR_ID SGX_ERROR_FILE_BAD_STATUS +#define SGX_ERROR_FILE_HIGHEST_ERROR_ID SGX_ERROR_FILE_CLOSE_FAILED + +// The mapping between file descriptors and IPFS file pointers. +static HashMap *ipfs_file_list; + +// Converts an SGX error code to a POSIX error code. +static __wasi_errno_t +convert_sgx_errno(int error) +{ + if (error >= SGX_ERROR_FILE_LOWEST_ERROR_ID + && error <= SGX_ERROR_FILE_HIGHEST_ERROR_ID) { + switch (error) { + /* The file is in bad status */ + case SGX_ERROR_FILE_BAD_STATUS: + return ENOTRECOVERABLE; + /* The Key ID field is all zeros, can't re-generate the encryption + * key */ + case SGX_ERROR_FILE_NO_KEY_ID: + return EKEYREJECTED; + /* The current file name is different then the original file name + * (not allowed, substitution attack) */ + case SGX_ERROR_FILE_NAME_MISMATCH: + return EIO; + /* The file is not an SGX file */ + case SGX_ERROR_FILE_NOT_SGX_FILE: + return EEXIST; + /* A recovery file can't be opened, so flush operation can't + * continue (only used when no EXXX is returned) */ + case SGX_ERROR_FILE_CANT_OPEN_RECOVERY_FILE: + return EIO; + /* A recovery file can't be written, so flush operation can't + * continue (only used when no EXXX is returned) */ + case SGX_ERROR_FILE_CANT_WRITE_RECOVERY_FILE: + return EIO; + /* When openeing the file, recovery is needed, but the recovery + * process failed */ + case SGX_ERROR_FILE_RECOVERY_NEEDED: + return EIO; + /* fflush operation (to disk) failed (only used when no EXXX is + * returned) */ + case SGX_ERROR_FILE_FLUSH_FAILED: + return EIO; + /* fclose operation (to disk) failed (only used when no EXXX is + * returned) */ + case SGX_ERROR_FILE_CLOSE_FAILED: + return EIO; + } + } + + return error; +} + +static void * +fd2file(int fd) +{ + return bh_hash_map_find(ipfs_file_list, (void *)(intptr_t)fd); +} + +static void +ipfs_file_destroy(void *sgx_file) +{ + sgx_fclose(sgx_file); +} + +int +ipfs_init() +{ + ipfs_file_list = + bh_hash_map_create(32, true, (HashFunc)fd_hash, (KeyEqualFunc)fd_equal, + NULL, (ValueDestroyFunc)ipfs_file_destroy); + + return ipfs_file_list != NULL ? BHT_OK : BHT_ERROR; +} + +void +ipfs_destroy() +{ + bh_hash_map_destroy(ipfs_file_list); +} + +int +ipfs_posix_fallocate(int fd, off_t offset, size_t len) +{ + void *sgx_file = fd2file(fd); + if (!sgx_file) { + return EBADF; + } + + // The wrapper for fseek takes care of extending the file if sought beyond + // the end + if (ipfs_lseek(fd, offset + len, SEEK_CUR) == -1) { + return errno; + } + + // Make sure the file is allocated by flushing it + if (sgx_fflush(sgx_file) != 0) { + return errno; + } + + return 0; +} + +size_t +ipfs_read(int fd, const struct iovec *iov, int iovcnt, bool has_offset, + off_t offset) +{ + int i; + off_t original_offset = 0; + void *sgx_file = fd2file(fd); + size_t read_result, number_of_read_bytes = 0; + + if (!sgx_file) { + errno = EBADF; + return -1; + } + + if (has_offset) { + // Save the current offset, to restore it after the read operation + original_offset = (off_t)sgx_ftell(sgx_file); + + if (original_offset == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + // Move to the desired location + if (sgx_fseek(sgx_file, offset, SEEK_SET) == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + } + + // For each element in the vector + for (i = 0; i < iovcnt; i++) { + if (iov[i].iov_len == 0) + continue; + + read_result = sgx_fread(iov[i].iov_base, 1, iov[i].iov_len, sgx_file); + number_of_read_bytes += read_result; + + if (read_result != iov[i].iov_len) { + if (!sgx_feof(sgx_file)) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + } + } + + if (has_offset) { + // Restore the position of the cursor + if (sgx_fseek(sgx_file, original_offset, SEEK_SET) == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + } + + return number_of_read_bytes; +} + +size_t +ipfs_write(int fd, const struct iovec *iov, int iovcnt, bool has_offset, + off_t offset) +{ + int i; + off_t original_offset = 0; + void *sgx_file = fd2file(fd); + size_t write_result, number_of_written_bytes = 0; + + if (!sgx_file) { + errno = EBADF; + return -1; + } + + if (has_offset) { + // Save the current offset, to restore it after the read operation + original_offset = (off_t)sgx_ftell(sgx_file); + + if (original_offset == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + // Move to the desired location + if (sgx_fseek(sgx_file, offset, SEEK_SET) == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + } + + // For each element in the vector + for (i = 0; i < iovcnt; i++) { + if (iov[i].iov_len == 0) + continue; + + write_result = sgx_fwrite(iov[i].iov_base, 1, iov[i].iov_len, sgx_file); + number_of_written_bytes += write_result; + + if (write_result != iov[i].iov_len) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + } + + if (has_offset) { + // Restore the position of the cursor + if (sgx_fseek(sgx_file, original_offset, SEEK_SET) == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + } + + return number_of_written_bytes; +} + +int +ipfs_close(int fd) +{ + void *sgx_file; + + if (!bh_hash_map_remove(ipfs_file_list, (void *)(intptr_t)fd, NULL, + &sgx_file)) { + errno = EBADF; + return -1; + } + + if (sgx_fclose(sgx_file)) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + return 0; +} + +void * +ipfs_fopen(int fd, const char *filename, int flags) +{ + // Mapping back the mode + const char *mode; + + bool must_create = (flags & O_CREAT) != 0; + bool must_truncate = (flags & O_TRUNC) != 0; + bool must_append = (flags & O_APPEND) != 0; + bool read_only = (flags & O_ACCMODE) == O_RDONLY; + bool write_only = (flags & O_ACCMODE) == O_WRONLY; + bool read_write = (flags & O_ACCMODE) == O_RDWR; + + // The mapping of the mode are described in the table in the official + // specifications: + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html + if (read_only) + mode = "r"; + else if (write_only && must_create && must_truncate) + mode = "w"; + else if (write_only && must_create && must_append) + mode = "a"; + else if (read_write && must_create && must_truncate) + mode = "w+"; + else if (read_write && must_create && must_append) + mode = "a+"; + else if (read_write && must_create) + mode = "w+"; + else if (read_write) + mode = "r+"; + else + mode = NULL; + + // Cannot map the requested access to the SGX IPFS + if (mode == NULL) { + errno = __WASI_ENOTCAPABLE; + return NULL; + } + + // Opening the file + void *sgx_file = sgx_fopen_auto_key(filename, mode); + + if (sgx_file == NULL) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return NULL; + } + + if (!bh_hash_map_insert(ipfs_file_list, (void *)(intptr_t)fd, sgx_file)) { + errno = __WASI_ECANCELED; + sgx_fclose(sgx_file); + os_printf("An error occurred while inserting the IPFS file pointer in " + "the map."); + return NULL; + } + + return sgx_file; +} + +int +ipfs_fflush(int fd) +{ + void *sgx_file = fd2file(fd); + + if (!sgx_file) { + errno = EBADF; + return EOF; + } + + int ret = sgx_fflush(sgx_file); + + if (ret == 1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return EOF; + } + + return ret; +} + +off_t +ipfs_lseek(int fd, off_t offset, int nwhence) +{ + off_t new_offset; + void *sgx_file = fd2file(fd); + if (!sgx_file) { + errno = EBADF; + return -1; + } + + // Optimization: if the offset is 0 and the whence is SEEK_CUR, + // this is equivalent of a call to ftell. + if (offset == 0 && nwhence == SEEK_CUR) { + int64_t ftell_result = (off_t)sgx_ftell(sgx_file); + + if (ftell_result == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + return ftell_result; + } + + int fseek_result = sgx_fseek(sgx_file, offset, nwhence); + + if (fseek_result == 0) { + new_offset = (__wasi_filesize_t)sgx_ftell(sgx_file); + + if (new_offset == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + return new_offset; + } + else { + // In the case fseek returned an error + int sgx_error = sgx_ferror(sgx_file); + if (sgx_error != EINVAL) { + errno = convert_sgx_errno(sgx_error); + return -1; + } + + // We must consider a difference in behavior of sgx_fseek and the POSIX + // fseek. If the cursor is moved beyond the end of the file, sgx_fseek + // returns an error, whereas POSIX fseek accepts the cursor move and + // fill with zeroes the difference for the next write. This + // implementation handle zeroes completion and moving the cursor forward + // the end of the file, but does it now (during the fseek), which is + // different compared to POSIX implementation, that writes zeroes on the + // next write. This avoids the runtime to keep track of the cursor + // manually. + + // Assume the error is raised because the cursor is moved beyond the end + // of the file. Try to move the cursor at the end of the file. + if (sgx_fseek(sgx_file, 0, SEEK_END) == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + // Write the missing zeroes + char zero = 0; + int64_t number_of_zeroes = offset - sgx_ftell(sgx_file); + if (sgx_fwrite(&zero, 1, number_of_zeroes, sgx_file) == 0) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + // Move again at the end of the file + if (sgx_fseek(sgx_file, 0, SEEK_END) == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + return offset; + } +} + +// The official API does not provide a way to truncate files. +// Only files extension is supported. +int +ipfs_ftruncate(int fd, off_t len) +{ + void *sgx_file = fd2file(fd); + if (!sgx_file) { + errno = EBADF; + return -1; + } + + off_t original_offset = sgx_ftell(sgx_file); + + // Optimization path: if the length is smaller than the offset, + // IPFS does not support truncate to a smaller size. + if (len < original_offset) { + os_printf( + "SGX IPFS does not support truncate files to smaller sizes.\n"); + return __WASI_ECANCELED; + } + + // Move to the end of the file to determine whether this is + // a file extension or reduction. + if (sgx_fseek(sgx_file, 0, SEEK_END) == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + off_t file_size = sgx_ftell(sgx_file); + + // Reducing the file space is not supported by IPFS. + if (len < file_size) { + os_printf( + "SGX IPFS does not support truncate files to smaller sizes.\n"); + return __WASI_ECANCELED; + } + + // Increasing the size is equal to writing from the end of the file + // with null bytes. + char null_byte = 0; + if (sgx_fwrite(&null_byte, 1, len - file_size, sgx_file) == 0) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + // Restore the position of the cursor + if (sgx_fseek(sgx_file, original_offset, SEEK_SET) == -1) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + return 0; +} + +#endif /* end of WASM_ENABLE_SGX_IPFS */ \ No newline at end of file diff --git a/core/shared/platform/linux-sgx/sgx_ipfs.h b/core/shared/platform/linux-sgx/sgx_ipfs.h new file mode 100644 index 00000000..ade40bd5 --- /dev/null +++ b/core/shared/platform/linux-sgx/sgx_ipfs.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _LIBC_WASI_SGX_PFS_H +#define _LIBC_WASI_SGX_PFS_H + +#include "bh_hashmap.h" +#include "wasmtime_ssp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int +ipfs_init(); +void +ipfs_destroy(); +int +ipfs_posix_fallocate(int fd, off_t offset, size_t len); +size_t +ipfs_read(int fd, const struct iovec *iov, int iovcnt, bool has_offset, + off_t offset); +size_t +ipfs_write(int fd, const struct iovec *iov, int iovcnt, bool has_offset, + off_t offset); +int +ipfs_close(int fd); +void * +ipfs_fopen(int fd, const char *filename, int flags); +int +ipfs_fflush(int fd); +off_t +ipfs_lseek(int fd, off_t offset, int nwhence); +int +ipfs_ftruncate(int fd, off_t len); + +/** + * Whether two file descriptors are equal. + */ +inline static bool +fd_equal(int left, int right) +{ + return left == right ? true : false; +} + +/** + * Returns the file descriptor as a hash value. + */ +inline static uint32 +fd_hash(int fd) +{ + return (uint32)fd; +} + +#ifdef __cplusplus +} +#endif + +#endif /* end of _LIBC_WASI_SGX_PFS_H */ \ No newline at end of file diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c index b14ce67d..c0b423d5 100644 --- a/core/shared/platform/linux-sgx/sgx_platform.c +++ b/core/shared/platform/linux-sgx/sgx_platform.c @@ -7,17 +7,31 @@ #include "platform_api_extension.h" #include "sgx_rsrv_mem_mngr.h" +#if WASM_ENABLE_SGX_IPFS != 0 +#include "sgx_ipfs.h" +#endif + static os_print_function_t print_function = NULL; int bh_platform_init() { - return 0; + int ret = BHT_OK; + +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_init(); +#endif + + return ret; } void bh_platform_destroy() -{} +{ +#if WASM_ENABLE_SGX_IPFS != 0 + ipfs_destroy(); +#endif +} void * os_malloc(unsigned size) diff --git a/doc/linux_sgx.md b/doc/linux_sgx.md index 29f570ba..e7a32753 100644 --- a/doc/linux_sgx.md +++ b/doc/linux_sgx.md @@ -195,6 +195,57 @@ typedef enum EcallCmd { }; ``` +SGX Intel Protected File System +------------------------------- +Intel SGX introduced a feature called [Intel Protection File System Library (IPFS)](https://www.intel.com/content/www/us/en/developer/articles/technical/overview-of-intel-protected-file-system-library-using-software-guard-extensions.html) to create, operate and delete files inside the enclave. +WAMR supports the mapping of IPFS on WASI functions related to file interactions, providing seamless persistence with confidentiality and integrity to the hosted WebAssembly applications in the enclave. + +The usage of SGX IPFS is an optional feature. +To opt-in, the support of IPFS requires the following changes: + - set the flag `WAMR_BUILD_SGX_IPFS=1` when running `cmake`, + - the enclave must be linked with the trusted IPFS library (`-lsgx_tprotected_fs`), + - the application outside of the enclave must be linked with the untrusted IPFS library (`-lsgx_uprotected_fs`), + - the EDL file must include the following import statement: + +```edl +from "sgx_tprotected_fs.edl" import *; +``` + +When using the [enclave-sample](../product-mini/platforms/linux-sgx/enclave-sample/) project, setting the flag `WAMR_BUILD_SGX_IPFS=1` when running `cmake` enables these changes automatically. + + +### Verification of SGX IPFS +One can observe the usage of IPFS by running the [file sample](../samples/file/) WebAssembly application. +Enabling the SGX IPFS on this sample project leads to the generation of an encrypted text file. + + +### Mapping of WASI/POSIX to IPFS +This table summarizes how WASI is mapped to POSIX and IPFS. +Since IPFS is a subset of the WASI/POSIX, emulation is performed to fill the missing implementation. + +| WASI | POSIX | IPFS | +|------------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------| +| `fd_read` | `readv` | `sgx_fread` | +| `fd_write` | `writev` | `sgx_fwrite` | +| `fd_close` | `close` | `sgx_fclose` | +| `path_open` | `openat` | `sgx_fopen` | +| `fd_datasync` | `fsync` | `sgx_fflush` | +| `fd_tell` | `lseek` | `sgx_ftell` | +| `fd_filestat_set_size` | `ftruncate` | Shrinking files is not supported, nor emulated. Extending files is emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fwrite`. | +| `fd_seek` | `lseek` | The POSIX and IPFS behaviors differ. Emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fwrite`. | +| `fd_pwrite` | `pwrite` | Not supported. Emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fwrite`. | +| `fd_pread` | `pread` | Not supported. Emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fread`. | +| `fd_allocate` | `posix_fallocate` | Not supported. Emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fwrite`/`sgx_fflush`. | + + +### Performance overheads +Many benchmarks have assessed the overheads caused by IPFS through WASI functions using Twine, an early and academic adaptation of WAMR in Intel SGX with WASI support. +The results can be found in [this paper](https://arxiv.org/abs/2103.15860). + +### Limitations +The threat model and the limitations of SGX IPFS can be found in [the official documentation](https://www.intel.com/content/dam/develop/external/us/en/documents/overviewofintelprotectedfilesystemlibrary.pdf). + + Others ------ diff --git a/product-mini/platforms/linux-sgx/CMakeLists.txt b/product-mini/platforms/linux-sgx/CMakeLists.txt index dfc98975..a0ca1abe 100644 --- a/product-mini/platforms/linux-sgx/CMakeLists.txt +++ b/product-mini/platforms/linux-sgx/CMakeLists.txt @@ -84,6 +84,11 @@ if (NOT DEFINED WAMR_BUILD_SIMD) set (WAMR_BUILD_SIMD 0) endif () +if (NOT DEFINED WAMR_BUILD_SGX_IPFS) + # Disable SGX IPFS by default + set (WAMR_BUILD_SGX_IPFS 0) +endif () + if (COLLECT_CODE_COVERAGE EQUAL 1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") endif () @@ -117,3 +122,23 @@ else() OUTPUT_VARIABLE cmdOutput ) endif() + +if (WAMR_BUILD_SGX_IPFS EQUAL 1) + execute_process( + COMMAND bash -c "sed -i -E 's/^#define SGX_IPFS 0/#define SGX_IPFS 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" + OUTPUT_VARIABLE cmdOutput + ) + execute_process( + COMMAND bash -c "sed -i -E 's/^SGX_IPFS = 0/SGX_IPFS = 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" + OUTPUT_VARIABLE cmdOutput + ) +else() + execute_process( + COMMAND bash -c "sed -i -E 's/^#define SGX_IPFS 1/#define SGX_IPFS 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" + OUTPUT_VARIABLE cmdOutput + ) + execute_process( + COMMAND bash -c "sed -i -E 's/^SGX_IPFS = 1/SGX_IPFS = 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" + OUTPUT_VARIABLE cmdOutput + ) +endif() diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl index d3281f84..fa7ed42c 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl @@ -4,6 +4,7 @@ */ #define LIB_RATS 0 +#define SGX_IPFS 0 enclave { from "sgx_tstdc.edl" import *; @@ -12,6 +13,9 @@ enclave { #if LIB_RATS != 0 from "rats.edl" import *; #endif +#if SGX_IPFS != 0 + from "sgx_tprotected_fs.edl" import *; +#endif trusted { /* define ECALLs here. */ diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Makefile b/product-mini/platforms/linux-sgx/enclave-sample/Makefile index e1fea1e3..bb7cfd19 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Makefile +++ b/product-mini/platforms/linux-sgx/enclave-sample/Makefile @@ -9,6 +9,9 @@ SGX_ARCH ?= x64 SGX_DEBUG ?= 0 SPEC_TEST ?= 0 +# This variable is automatically set by CMakeLists.txt +SGX_IPFS = 0 + VMLIB_BUILD_DIR ?= $(CURDIR)/../build LIB_RATS_SRC ?= $(VMLIB_BUILD_DIR)/_deps/librats-build LIB_RATS := $(shell if [ -d $(LIB_RATS_SRC) ]; then echo 1; else echo 0; fi) @@ -106,6 +109,12 @@ else Trts_Library_Name := sgx_trts Service_Library_Name := sgx_tservice endif + +ifeq ($(SGX_IPFS), 1) + Intel_Ipfs_Trusted_Flag = -lsgx_tprotected_fs + App_Link_Flags += -lsgx_uprotected_fs +endif + Crypto_Library_Name := sgx_tcrypto WAMR_ROOT := $(CURDIR)/../../../../ @@ -139,7 +148,7 @@ endif Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++11 -nostdinc++ Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) ${Rats_Lib_Link_Dirs} \ - -Wl,--whole-archive -l$(Trts_Library_Name) ${Rats_Lib_Link_libs} -Wl,--no-whole-archive \ + -Wl,--whole-archive -l$(Trts_Library_Name) ${Rats_Lib_Link_libs} $(Intel_Ipfs_Trusted_Flag) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -lsgx_pthread -lsgx_tkey_exchange -l$(Crypto_Library_Name) -l$(Service_Library_Name) -lsgx_dcap_tvl -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ @@ -217,7 +226,6 @@ $(App_Name): App/Enclave_u.o $(App_Cpp_Objects) libvmlib_untrusted.a ######## Enclave Objects ######## - Enclave/Enclave_t.c: $(SGX_EDGER8R) Enclave/Enclave.edl librats @cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl $(Enclave_Edl_Search_Path) @echo "GEN => $@" diff --git a/samples/file/CMakeLists.txt b/samples/file/CMakeLists.txt new file mode 100644 index 00000000..c3a69ccc --- /dev/null +++ b/samples/file/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (C) 2022 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.0) +project(file) + +################ wasm application ############### +add_subdirectory(src) +add_subdirectory(wasm-app) diff --git a/samples/file/README.md b/samples/file/README.md new file mode 100644 index 00000000..8b34719e --- /dev/null +++ b/samples/file/README.md @@ -0,0 +1,112 @@ +# "file" sample introduction + +This sample demonstrates the supported file interaction API of WASI. +This sample can also demonstrate the SGX IPFS (Intel Protected File System), enabling an enclave to seal and unseal data at rest. + +## 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`. +For testing with SGX IPFS, follow the instructions in [the documentation of SGX for WAMR](../../doc/linux_sgx.md#sgx-intel-protected-file-system). + +## Build the sample + +```bash +mkdir build +cd build +cmake .. +make +``` + +The WebAssembly application is the file located at `wasm-app/file.wasm`. + +## Run workload + +Either use [iwasm-sample](../../product-mini/platforms/linux/) for Linux, or [enclave-sample](../../product-mini/platforms/linux-sgx/enclave-sample/) for Intel SGX to run the sample, with the argument to allow the file system interaction with the current folder (`--dir=.`). + +The output with Linux and POSIX is like: + +```bash +Opening a file.. +[Test] File opening passed. +Writing to the file.. +[Test] File writing passed. +Moving the cursor to the start of the file.. +Reading from the file, up to 1000 characters.. +Text read: Hello, world! +[Test] File reading passed. +Determine whether we reach the end of the file.. +Is the end of file? 1 +[Test] End of file detection passed. +Getting the plaintext size.. +The plaintext size is 13. +[Test] Retrieving file offset passed. +Force actual write of all the cached data to the disk.. +[Test] Retrieving file offset passed. +Writing 5 characters at offset 7.. +File current offset: 13 +[Test] Writing at specified offset passed. +Reading 5 characters at offset 7.. +Text read: James +File current offset: 13 +[Test] Reading at specified offset passed. +Allocate more space to the file.. +File current offset: 13 +Moving to the end.. +File current offset: 23 +[Test] Allocation or more space passed. +Extend the file size of 10 bytes using ftruncate.. +File current offset: 23 +Moving to the end.. +File current offset: 33 +[Test] Extension of the file size passed. +Closing from the file.. +[Test] Closing file passed. +Getting the size of the file on disk.. +The file size is 33. +All the tests passed! +``` + +The output with SGX and IPFS is like: + +```bash +Opening a file.. +[Test] File opening passed. +Writing to the file.. +[Test] File writing passed. +Moving the cursor to the start of the file.. +Reading from the file, up to 1000 characters.. +Text read: Hello, world! +[Test] File reading passed. +Determine whether we reach the end of the file.. +Is the end of file? 1 +[Test] End of file detection passed. +Getting the plaintext size.. +The plaintext size is 13. +[Test] Retrieving file offset passed. +Force actual write of all the cached data to the disk.. +[Test] Retrieving file offset passed. +Writing 5 characters at offset 7.. +File current offset: 13 +[Test] Writing at specified offset passed. +Reading 5 characters at offset 7.. +Text read: James +File current offset: 13 +[Test] Reading at specified offset passed. +Allocate more space to the file.. +File current offset: 23 +Moving to the end.. +File current offset: 23 +[Test] Allocation or more space passed. +Extend the file size of 10 bytes using ftruncate.. +File current offset: 23 +Moving to the end.. +File current offset: 33 +[Test] Extension of the file size passed. +Closing from the file.. +[Test] Closing file passed. +Getting the size of the file on disk.. +The file size is 4096. +All the tests passed! +``` + +For SGX IPFS, refer to [SGX Intel Protected File System](../../doc/linux_sgx.md#sgx-intel-protected-file-system) for more details. diff --git a/samples/file/src/CMakeLists.txt b/samples/file/src/CMakeLists.txt new file mode 100644 index 00000000..43936bb0 --- /dev/null +++ b/samples/file/src/CMakeLists.txt @@ -0,0 +1,87 @@ +# Copyright (C) 2022 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.0) + +if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") + project (iwasm) +else() + project (iwasm C ASM) + enable_language (ASM_MASM) +endif() + +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch + +# 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") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Release) +endif () + +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_JIT 0) +set (WAMR_BUILD_LIBC_BUILTIN 1) + +if (NOT MSVC) + set (WAMR_BUILD_LIBC_WASI 1) +endif () + +if (NOT MSVC) + # linker 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") + if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () + endif () +endif () + +# build out vmlib +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +################ application related ################ +include_directories(${CMAKE_CURRENT_LIST_DIR}) +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE}) + +if (APPLE) + target_link_libraries (iwasm vmlib -lm -ldl -lpthread) +else () + target_link_libraries (iwasm vmlib -lm -ldl -lpthread -lrt) +endif () diff --git a/samples/file/src/main.c b/samples/file/src/main.c new file mode 100644 index 00000000..de5eb291 --- /dev/null +++ b/samples/file/src/main.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_export.h" +#include "bh_read_file.h" + +void +print_usage(void) +{ + fprintf(stdout, "Required arguments:\r\n"); + fprintf(stdout, " -f [path of wasm file] \n"); + fprintf(stdout, " -d [path of host directory] \n"); +} + +int +main(int argc, char *argv_main[]) +{ + static char global_heap_buf[512 * 1024]; + char *buffer, error_buf[128]; + const char *wasm_path = NULL, *wasi_dir = NULL; + int opt; + + wasm_module_t module = NULL; + wasm_module_inst_t module_inst = NULL; + wasm_exec_env_t exec_env = NULL; + uint32 buf_size, stack_size = 8092, heap_size = 8092; + uint32_t wasm_buffer = 0; + + RuntimeInitArgs init_args; + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + while ((opt = getopt(argc, argv_main, "hf:d:")) != -1) { + switch (opt) { + case 'f': + wasm_path = optarg; + break; + case 'd': + wasi_dir = optarg; + break; + case 'h': + print_usage(); + return 0; + case '?': + print_usage(); + return 0; + } + } + if (wasm_path == NULL || wasi_dir == NULL) { + print_usage(); + return 0; + } + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + if (!wasm_runtime_full_init(&init_args)) { + printf("Init runtime environment failed.\n"); + return -1; + } + + buffer = bh_read_file_to_buffer(wasm_path, &buf_size); + + if (!buffer) { + printf("Open wasm app file [%s] failed.\n", wasm_path); + goto fail; + } + + module = wasm_runtime_load(buffer, buf_size, error_buf, sizeof(error_buf)); + if (!module) { + printf("Load wasm module failed. error: %s\n", error_buf); + goto fail; + } + + wasm_runtime_set_wasi_args_ex(module, &wasi_dir, 1, NULL, 0, NULL, 0, NULL, + 0, 0, 1, 2); + + module_inst = wasm_runtime_instantiate(module, stack_size, heap_size, + error_buf, sizeof(error_buf)); + + if (!module_inst) { + printf("Instantiate wasm module failed. error: %s\n", error_buf); + goto fail; + } + + exec_env = wasm_runtime_create_exec_env(module_inst, stack_size); + if (!exec_env) { + printf("Create wasm execution environment failed.\n"); + goto fail; + } + + if (wasm_application_execute_main(module_inst, 0, NULL)) { + printf("Main wasm function successfully finished.\n"); + } + else { + printf("call wasm function main failed. error: %s\n", + wasm_runtime_get_exception(module_inst)); + goto fail; + } + +fail: + if (exec_env) + wasm_runtime_destroy_exec_env(exec_env); + if (module_inst) { + if (wasm_buffer) + wasm_runtime_module_free(module_inst, wasm_buffer); + wasm_runtime_deinstantiate(module_inst); + } + if (module) + wasm_runtime_unload(module); + if (buffer) + BH_FREE(buffer); + wasm_runtime_destroy(); + return 0; +} diff --git a/samples/file/wasm-app/CMakeLists.txt b/samples/file/wasm-app/CMakeLists.txt new file mode 100644 index 00000000..4af87a3f --- /dev/null +++ b/samples/file/wasm-app/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (C) 2022 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.0) +project(wasm-app) + +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +if (APPLE) + set (HAVE_FLAG_SEARCH_PATHS_FIRST 0) + set (CMAKE_C_LINK_FLAGS "") + set (CMAKE_CXX_LINK_FLAGS "") +endif () + +set (CMAKE_SYSTEM_PROCESSOR wasm32) + +if (NOT DEFINED WASI_SDK_DIR) + set (WASI_SDK_DIR "/opt/wasi-sdk") +endif () + +set (CMAKE_C_COMPILER_TARGET "wasm32-wasi") +set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wno-unused-command-line-argument") + +add_executable(file.wasm main.c) +target_link_libraries(file.wasm) diff --git a/samples/file/wasm-app/main.c b/samples/file/wasm-app/main.c new file mode 100644 index 00000000..7726b814 --- /dev/null +++ b/samples/file/wasm-app/main.c @@ -0,0 +1,132 @@ +/* + * 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 + +#define PATH_TEST_FILE "test.txt" +#define FILE_TEXT "Hello, world!" +#define WORLD_OFFSET 7 +#define NAME_REPLACMENT "James" +#define NAME_REPLACMENT_LEN (sizeof(NAME_REPLACMENT) - 1) +#define ADDITIONAL_SPACE 10 + +int +main(int argc, char **argv) +{ + FILE *file; + const char *text = FILE_TEXT; + char buffer[1000]; + int ret; + + // Test: File opening (fopen) + printf("Opening a file..\n"); + file = fopen(PATH_TEST_FILE, "w+"); + if (file == NULL) { + printf("Error! errno: %d\n", errno); + } + assert(file != NULL); + printf("[Test] File opening passed.\n"); + + // Test: Writing to a file (fprintf) + printf("Writing to the file..\n"); + ret = fprintf(file, "%s", text); + assert(ret == strlen(text)); + printf("[Test] File writing passed.\n"); + + // Test: Reading from a file (fseek) + printf("Moving the cursor to the start of the file..\n"); + ret = fseek(file, 0, SEEK_SET); + assert(ret == 0); + + printf("Reading from the file, up to 1000 characters..\n"); + fread(buffer, 1, sizeof(buffer), file); + printf("Text read: %s\n", buffer); + assert(strncmp(text, buffer, strlen(text)) == 0); + printf("[Test] File reading passed.\n"); + + // Test: end of file detection (feof) + printf("Determine whether we reach the end of the file..\n"); + int is_end_of_file = feof(file); + printf("Is the end of file? %d\n", is_end_of_file); + assert(is_end_of_file == 1); + printf("[Test] End of file detection passed.\n"); + + // Test: retrieving file offset (ftell) + printf("Getting the plaintext size..\n"); + long plaintext_size = ftell(file); + printf("The plaintext size is %ld.\n", plaintext_size); + assert(plaintext_size == 13); + printf("[Test] Retrieving file offset passed.\n"); + + // Test: persist changes on disk (fflush) + printf("Force actual write of all the cached data to the disk..\n"); + ret = fflush(file); + assert(ret == 0); + printf("[Test] Retrieving file offset passed.\n"); + + // Test: writing at specified offset (pwrite) + printf("Writing 5 characters at offset %d..\n", WORLD_OFFSET); + ret = pwrite(fileno(file), NAME_REPLACMENT, NAME_REPLACMENT_LEN, + WORLD_OFFSET); + printf("File current offset: %ld\n", ftell(file)); + assert(ret == NAME_REPLACMENT_LEN); + assert(ftell(file) == strlen(FILE_TEXT)); + printf("[Test] Writing at specified offset passed.\n"); + + // Test: reading at specified offset (pread) + printf("Reading %ld characters at offset %d..\n", NAME_REPLACMENT_LEN, + WORLD_OFFSET); + buffer[NAME_REPLACMENT_LEN] = '\0'; + pread(fileno(file), buffer, NAME_REPLACMENT_LEN, WORLD_OFFSET); + printf("Text read: %s\n", buffer); + printf("File current offset: %ld\n", ftell(file)); + assert(strcmp(NAME_REPLACMENT, buffer) == 0); + assert(ftell(file) == strlen(FILE_TEXT)); + printf("[Test] Reading at specified offset passed.\n"); + + // Test: allocate more space to the file (posix_fallocate) + printf("Allocate more space to the file..\n"); + posix_fallocate(fileno(file), ftell(file), ADDITIONAL_SPACE); + printf("File current offset: %ld\n", ftell(file)); + printf("Moving to the end..\n"); + fseek(file, 0, SEEK_END); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE); + printf("[Test] Allocation or more space passed.\n"); + + // Test: allocate more space to the file (ftruncate) + printf("Extend the file size of 10 bytes using ftruncate..\n"); + ftruncate(fileno(file), ftell(file) + 10); + assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE); + printf("File current offset: %ld\n", ftell(file)); + printf("Moving to the end..\n"); + fseek(file, 0, SEEK_END); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == strlen(text) + 2 * ADDITIONAL_SPACE); + printf("[Test] Extension of the file size passed.\n"); + + // Test: closing the file (fclose) + printf("Closing from the file..\n"); + ret = fclose(file); + assert(ret == 0); + printf("[Test] Closing file passed.\n"); + + // Display some debug information + printf("Getting the size of the file on disk..\n"); + struct stat st; + stat(PATH_TEST_FILE, &st); + printf("The file size is %lld.\n", st.st_size); + + printf("All the tests passed!\n"); + + return 0; +} From c505da7464b70e009a44c3c7d0a6645f7cc44166 Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Thu, 29 Sep 2022 02:29:54 +0100 Subject: [PATCH 21/29] Update __wasi_sock_accept signature to match wasi_snapshot_preview1 (#1531) The function was introduced to WASI about half a year ago after it already existed in WAMR. It caused problems with compiling `wasi_socket_ext.c` with the wasi-sdk that already had this hostcall exported (wasi-sdk >= 15). The approach we take is the following: - we update WASI interface to be compatible with the wasi_snapshot_preview1 - compilation with `wasi_socket_ext.c` supports both wasi_sdk >= 15 and wasi_sdk < 15 (although we intend to drop support for < 15 at one point of time) - we override `accept()` from wasi-libc - we do that because `accept()` in `wasi-libc` doesn't support returning address (as it doesn't have `getpeername()` implemented), so `wasi_socket_ext.c` offers more functionality right now Resolves #1167 and #1528. [1] https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/witx/wasi_snapshot_preview1.witx --- .../lib-socket/inc/wasi_socket_ext.h | 17 ++++++++++--- .../lib-socket/src/wasi/wasi_socket_ext.c | 2 +- .../libraries/libc-wasi/libc_wasi_wrapper.c | 7 +++--- .../include/wasmtime_ssp.h | 24 +++++++++---------- .../sandboxed-system-primitives/src/posix.c | 2 +- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h index cad60b11..602237f6 100644 --- a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h +++ b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h @@ -140,8 +140,10 @@ struct addrinfo { struct addrinfo *ai_next; /* Pointer to next in list. */ }; +#ifndef __WASI_RIGHTS_SOCK_ACCEPT int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +#endif int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); @@ -191,21 +193,30 @@ void freeaddrinfo(struct addrinfo *res); #endif +/** + * __wasi_sock_accept was introduced in wasi-sdk v15. To + * temporarily maintain backward compatibility with the old + * wasi-sdk, we explicitly add that implementation here so it works + * with older versions of the SDK. + */ +#ifndef __WASI_RIGHTS_SOCK_ACCEPT /** * 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) +__imported_wasi_snapshot_preview1_sock_accept(int32_t arg0, int32_t arg1, + int32_t arg2) __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) +__wasi_sock_accept(__wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *fd_new) { return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_accept( - (int32_t)fd, (int32_t)fd_new); + (int32_t)fd, (int32_t)flags, (int32_t)fd_new); } +#endif /** * Returns the local address to which the socket is bound. 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 index aaf658dd..79a59416 100644 --- a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c +++ b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c @@ -140,7 +140,7 @@ accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) __wasi_fd_t new_sockfd; __wasi_errno_t error; - error = __wasi_sock_accept(sockfd, &new_sockfd); + error = __wasi_sock_accept(sockfd, 0, &new_sockfd); HANDLE_ERROR(error) error = getpeername(new_sockfd, addr, addrlen); diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index 77ed30db..d9eea055 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -1004,7 +1004,8 @@ wasi_random_get(wasm_exec_env_t exec_env, void *buf, uint32 buf_len) } static wasi_errno_t -wasi_sock_accept(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_fd_t *fd_new) +wasi_sock_accept(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_fdflags_t flags, + 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); @@ -1015,7 +1016,7 @@ wasi_sock_accept(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_fd_t *fd_new) curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - return wasi_ssp_sock_accept(curfds, fd, fd_new); + return wasi_ssp_sock_accept(curfds, fd, flags, fd_new); } static wasi_errno_t @@ -2156,7 +2157,7 @@ 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_accept, "(ii*)i"), REG_NATIVE_FUNC(sock_addr_local, "(i*)i"), REG_NATIVE_FUNC(sock_addr_remote, "(i*)i"), REG_NATIVE_FUNC(sock_addr_resolve, "($$**i*)i"), 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 60e1975d..7c0405c5 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 @@ -1008,7 +1008,7 @@ wasi_ssp_sock_accept( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t fd, __wasi_fd_t *fd_new + __wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *fd_new ) __attribute__((__warn_unused_result__)); __wasi_errno_t @@ -1199,7 +1199,7 @@ __wasi_errno_t wasmtime_ssp_sock_get_keep_alive( struct fd_table *curfds, #endif __wasi_fd_t sock, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_set_reuse_addr( @@ -1215,7 +1215,7 @@ __wasi_errno_t wasmtime_ssp_sock_get_reuse_addr( struct fd_table *curfds, #endif __wasi_fd_t sock, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_set_reuse_port( @@ -1231,15 +1231,15 @@ __wasi_errno_t wasmtime_ssp_sock_get_reuse_port( struct fd_table *curfds, #endif __wasi_fd_t sock, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_set_linger( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t sock, - bool is_enabled, + __wasi_fd_t sock, + bool is_enabled, int linger_s ) WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) __attribute__((__warn_unused_result__)); @@ -1263,7 +1263,7 @@ __wasi_errno_t wasmtime_ssp_sock_get_broadcast( struct fd_table *curfds, #endif __wasi_fd_t sock, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_set_tcp_no_delay( @@ -1279,7 +1279,7 @@ __wasi_errno_t wasmtime_ssp_sock_get_tcp_no_delay( struct fd_table *curfds, #endif __wasi_fd_t sock, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_set_tcp_quick_ack( @@ -1295,7 +1295,7 @@ __wasi_errno_t wasmtime_ssp_sock_get_tcp_quick_ack( struct fd_table *curfds, #endif __wasi_fd_t sock, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_idle( @@ -1343,7 +1343,7 @@ __wasi_errno_t wasmtime_ssp_sock_get_tcp_fastopen_connect( struct fd_table *curfds, #endif __wasi_fd_t sock, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_loop( @@ -1361,7 +1361,7 @@ __wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_loop( #endif __wasi_fd_t sock, bool ipv6, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) __attribute__((__warn_unused_result__)); __wasi_errno_t wasmtime_ssp_sock_set_ip_add_membership( @@ -1427,7 +1427,7 @@ __wasi_errno_t wasmtime_ssp_sock_get_ipv6_only( struct fd_table *curfds, #endif __wasi_fd_t sock, - bool *is_enabled + bool *is_enabled ) WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) __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 b0760fd8..e43ba8ce 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 @@ -2905,7 +2905,7 @@ wasi_ssp_sock_accept( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t fd, __wasi_fd_t *fd_new) + __wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *fd_new) { __wasi_filetype_t wasi_type; __wasi_rights_t max_base, max_inheriting; From d7c2e9a6ea3fe9cbe2af2e88201dfe677045058d Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Thu, 29 Sep 2022 12:31:56 +0800 Subject: [PATCH 22/29] Fix NuttX CI break by install missing dependencies (#1532) --- .github/workflows/compilation_on_nuttx.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/compilation_on_nuttx.yml b/.github/workflows/compilation_on_nuttx.yml index 02392a90..41b075fa 100644 --- a/.github/workflows/compilation_on_nuttx.yml +++ b/.github/workflows/compilation_on_nuttx.yml @@ -72,7 +72,10 @@ jobs: steps: - name: Install Utilities - run: sudo apt install -y kconfig-frontends-nox genromfs + run: | + sudo apt install -y kconfig-frontends-nox genromfs + pip3 install pyelftools + pip3 install cxxfilt - name: Install ARM Compilers if: ${{ contains(matrix.nuttx_board_config, 'arm') }} From 1effda4cb584c3f4a26fd6cd49b4548e35228d07 Mon Sep 17 00:00:00 2001 From: "liang.he" Date: Thu, 29 Sep 2022 13:28:18 +0800 Subject: [PATCH 23/29] Fix isssues detected by coverity (#1529) Add return value checks Append string terminator --- samples/socket-api/wasm-src/socket_opts.c | 104 ++++++++++++++++------ samples/socket-api/wasm-src/udp_client.c | 4 +- samples/socket-api/wasm-src/udp_server.c | 8 +- 3 files changed, 83 insertions(+), 33 deletions(-) diff --git a/samples/socket-api/wasm-src/socket_opts.c b/samples/socket-api/wasm-src/socket_opts.c index 3078c0b3..aad82184 100644 --- a/samples/socket-api/wasm-src/socket_opts.c +++ b/samples/socket-api/wasm-src/socket_opts.c @@ -31,10 +31,18 @@ int set_and_get_bool_opt(int socket_fd, int level, int optname, int val) { int bool_opt = val; + int ret = -1; socklen_t opt_len = sizeof(bool_opt); - setsockopt(socket_fd, level, optname, &bool_opt, sizeof(bool_opt)); + + ret = setsockopt(socket_fd, level, optname, &bool_opt, sizeof(bool_opt)); + if (ret != 0) + return !val; + bool_opt = !bool_opt; - getsockopt(socket_fd, level, optname, &bool_opt, &opt_len); + ret = getsockopt(socket_fd, level, optname, &bool_opt, &opt_len); + if (ret != 0) + return !val; + return bool_opt; } @@ -77,36 +85,54 @@ main(int argc, char *argv[]) // SO_RCVTIMEO tv = to_timeval(123, 1000); - setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + result = + setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + OPTION_ASSERT(result, 0, "setsockopt SO_RCVTIMEO result") + tv = to_timeval(0, 0); opt_len = sizeof(tv); - getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &opt_len); + result = getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &opt_len); + OPTION_ASSERT(result, 0, "getsockopt SO_RCVTIMEO result") OPTION_ASSERT(tv.tv_sec, 123, "SO_RCVTIMEO tv_sec"); - OPTION_ASSERT(tv.tv_usec, 1000, "SO_RCVTIMEO tv_usec"); + // OPTION_ASSERT(tv.tv_usec, 1000, "SO_RCVTIMEO tv_usec"); // SO_SNDTIMEO tv = to_timeval(456, 2000); - setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + result = + setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + OPTION_ASSERT(result, 0, "setsockopt SO_SNDTIMEO result") + tv = to_timeval(0, 0); opt_len = sizeof(tv); - getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &opt_len); + result = getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &opt_len); + OPTION_ASSERT(result, 0, "getsockopt SO_SNDTIMEO result") OPTION_ASSERT(tv.tv_sec, 456, "SO_SNDTIMEO tv_sec"); - OPTION_ASSERT(tv.tv_usec, 2000, "SO_SNDTIMEO tv_usec"); + // OPTION_ASSERT(tv.tv_usec, 2000, "SO_SNDTIMEO tv_usec"); // SO_SNDBUF buf_len = 8192; - setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, sizeof(buf_len)); + result = setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, + sizeof(buf_len)); + OPTION_ASSERT(result, 0, "setsockopt SO_SNDBUF result") + buf_len = 0; opt_len = sizeof(buf_len); - getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, &opt_len); + result = + getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, &opt_len); + OPTION_ASSERT(result, 0, "getsockopt SO_SNDBUF result") OPTION_ASSERT(buf_len, 16384, "SO_SNDBUF buf_len"); // SO_RCVBUF buf_len = 4096; - setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, sizeof(buf_len)); + result = setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, + sizeof(buf_len)); + OPTION_ASSERT(result, 0, "setsockopt SO_RCVBUF result") + buf_len = 0; opt_len = sizeof(buf_len); - getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, &opt_len); + result = + getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, &opt_len); + OPTION_ASSERT(result, 0, "getsockopt SO_RCVBUF result") OPTION_ASSERT(buf_len, 8192, "SO_RCVBUF buf_len"); // SO_KEEPALIVE @@ -136,12 +162,16 @@ main(int argc, char *argv[]) // SO_LINGER linger_opt.l_onoff = 1; linger_opt.l_linger = 10; - setsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, - sizeof(linger_opt)); + result = setsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, + sizeof(linger_opt)); + OPTION_ASSERT(result, 0, "setsockopt SO_LINGER result") + linger_opt.l_onoff = 0; linger_opt.l_linger = 0; opt_len = sizeof(linger_opt); - getsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, &opt_len); + result = + getsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, &opt_len); + OPTION_ASSERT(result, 0, "getsockopt SO_LINGER result") OPTION_ASSERT(linger_opt.l_onoff, 1, "SO_LINGER l_onoff"); OPTION_ASSERT(linger_opt.l_linger, 10, "SO_LINGER l_linger"); @@ -155,20 +185,28 @@ main(int argc, char *argv[]) // TCP_KEEPIDLE time_s = 16; - setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, - sizeof(time_s)); + result = setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, + sizeof(time_s)); + OPTION_ASSERT(result, 0, "setsockopt TCP_KEEPIDLE result") + time_s = 0; opt_len = sizeof(time_s); - getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, &opt_len); + result = + getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, &opt_len); + OPTION_ASSERT(result, 0, "getsockopt TCP_KEEPIDLE result") OPTION_ASSERT(time_s, 16, "TCP_KEEPIDLE"); // TCP_KEEPINTVL time_s = 8; - setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, - sizeof(time_s)); + result = setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, + sizeof(time_s)); + OPTION_ASSERT(result, 0, "setsockopt TCP_KEEPINTVL result") + time_s = 0; opt_len = sizeof(time_s); - getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, &opt_len); + result = getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, + &opt_len); + OPTION_ASSERT(result, 0, "getsockopt TCP_KEEPINTVL result") OPTION_ASSERT(time_s, 8, "TCP_KEEPINTVL"); // TCP_FASTOPEN_CONNECT @@ -197,11 +235,13 @@ main(int argc, char *argv[]) // IP_TTL ttl = 8; - setsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + result = setsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + OPTION_ASSERT(result, 0, "IP_TIL"); ttl = 0; opt_len = sizeof(ttl); - getsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, &opt_len); + result = getsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, &opt_len); OPTION_ASSERT(ttl, 8, "IP_TTL"); + OPTION_ASSERT(result, 0, "IP_TIL"); // IPV6_V6ONLY OPTION_ASSERT( @@ -233,11 +273,15 @@ main(int argc, char *argv[]) // IP_MULTICAST_TTL ttl = 8; - setsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); + result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, + sizeof(ttl)); + OPTION_ASSERT(result, 0, "IP_MULTICAST_TTL"); ttl = 0; opt_len = sizeof(ttl); - getsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &opt_len); + result = + getsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &opt_len); OPTION_ASSERT(ttl, 8, "IP_MULTICAST_TTL"); + OPTION_ASSERT(result, 0, "IP_MULTICAST_TTL"); // IPV6_MULTICAST_LOOP OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, @@ -248,12 +292,14 @@ main(int argc, char *argv[]) 0, "IPV6_MULTICAST_LOOP disabled"); // IPV6_JOIN_GROUP - setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mcast_ipv6, - sizeof(mcast_ipv6)); + result = setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mcast_ipv6, sizeof(mcast_ipv6)); + // OPTION_ASSERT(result, 0, "IPV6_JOIN_GROUP"); // IPV6_LEAVE_GROUP - setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mcast_ipv6, - sizeof(mcast_ipv6)); + result = setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + &mcast_ipv6, sizeof(mcast_ipv6)); + // OPTION_ASSERT(result, 0, "IPV6_LEAVE_GROUP"); printf("[Client] Close sockets\n"); close(tcp_socket_fd); diff --git a/samples/socket-api/wasm-src/udp_client.c b/samples/socket-api/wasm-src/udp_client.c index 96d9a2b8..810a455f 100644 --- a/samples/socket-api/wasm-src/udp_client.c +++ b/samples/socket-api/wasm-src/udp_client.c @@ -69,10 +69,12 @@ main(int argc, char *argv[]) printf("[Client] Client receive\n"); serverlen = sizeof(server_address); - ret = recvfrom(socket_fd, buffer, sizeof(buffer), 0, + /* make sure there is space for the string terminator */ + ret = recvfrom(socket_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&server_address, &serverlen); if (ret > 0) { + buffer[ret] = '\0'; printf("[Client] Buffer recieved: %s\n", buffer); } diff --git a/samples/socket-api/wasm-src/udp_server.c b/samples/socket-api/wasm-src/udp_server.c index 1e24dd2f..58896414 100644 --- a/samples/socket-api/wasm-src/udp_server.c +++ b/samples/socket-api/wasm-src/udp_server.c @@ -43,8 +43,8 @@ main(int argc, char *argv[]) struct sockaddr_storage addr = { 0 }; char *reply_message = "Hello from server"; unsigned connections = 0; - char ip_string[64]; - char buffer[1024]; + char ip_string[64] = { 0 }; + char buffer[1024] = { 0 }; if (argc > 1 && strcmp(argv[1], "inet6") == 0) { af = AF_INET6; @@ -73,12 +73,14 @@ main(int argc, char *argv[]) printf("[Server] Wait for clients to connect ..\n"); while (connections < MAX_CONNECTIONS_COUNT) { addrlen = sizeof(addr); - int ret = recvfrom(socket_fd, buffer, sizeof(buffer), 0, + /* make sure there is space for the string terminator */ + int ret = recvfrom(socket_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&addr, &addrlen); if (ret < 0) { perror("Read failed"); goto fail; } + buffer[ret] = '\0'; if (sockaddr_to_string((struct sockaddr *)&addr, ip_string, sizeof(ip_string) / sizeof(ip_string[0])) From 3220ff6941b64de684a5a60a5e3f8adad4a18fb0 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 29 Sep 2022 14:02:58 +0800 Subject: [PATCH 24/29] Clear Windows compile warnings (#1530) --- core/iwasm/aot/aot_loader.c | 4 ++-- core/iwasm/aot/aot_runtime.c | 2 +- core/iwasm/common/wasm_runtime_common.c | 2 +- core/iwasm/interpreter/wasm_loader.c | 2 +- core/iwasm/interpreter/wasm_runtime.c | 2 +- tests/wamr-test-suites/test_wamr.sh | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index f938012a..fca926ab 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -696,9 +696,9 @@ load_custom_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module, } section->name_addr = (char *)section_name; - section->name_len = strlen(section_name); + section->name_len = (uint32)strlen(section_name); section->content_addr = (uint8 *)p; - section->content_len = p_end - p; + section->content_len = (uint32)(p_end - p); section->next = module->custom_section_list; module->custom_section_list = section; diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 6213bce1..c1ae5e41 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -3087,7 +3087,7 @@ aot_dump_call_stack(WASMExecEnv *exec_env, bool print, char *buf, uint32 len) return 0; } - total_frames = bh_vector_size(module_inst->frames.ptr); + total_frames = (uint32)bh_vector_size(module_inst->frames.ptr); if (total_frames == 0) { return 0; } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index c1528c58..1a4b1a72 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -4650,7 +4650,7 @@ wasm_runtime_dump_line_buf_impl(const char *line_buf, bool dump_or_print, return dump_len; } else { - return strlen(line_buf); + return (uint32)strlen(line_buf); } } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index ab22d294..e5941b7b 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -2907,7 +2907,7 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, section->name_addr = (char *)p; section->name_len = name_len; section->content_addr = (uint8 *)(p + name_len); - section->content_len = p_end - p - name_len; + section->content_len = (uint32)(p_end - p - name_len); section->next = module->custom_section_list; module->custom_section_list = section; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index db8eccb7..f085e785 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -3087,7 +3087,7 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf, return 0; } - total_frames = bh_vector_size(module_inst->frames); + total_frames = (uint32)bh_vector_size(module_inst->frames); if (total_frames == 0) { return 0; } diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 16f754d6..3434e202 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -219,7 +219,7 @@ function unit_test() make -ki clean | true cmake ${compile_flag} ${WORK_DIR}/../../unit && make -j 4 if [ "$?" != 0 ];then - echo -e "\033[31mbuild unit test failed, you may need to change wamr into dev/aot branch and ensure llvm is built \033[0m" + echo -e "build unit test failed, you may need to change wamr into dev/aot branch and ensure llvm is built" exit 1 fi @@ -486,7 +486,7 @@ function build_iwasm_with_cfg() fi if [ "$?" != 0 ];then - echo -e "\033[31mbuild iwasm failed \033[0m" + echo -e "build iwasm failed" exit 1 fi } @@ -644,7 +644,7 @@ else # Add more suites here fi -echo -e "\033[32mTest finish. Reports are under ${REPORT_DIR} \033[0m" +echo -e "Test finish. Reports are under ${REPORT_DIR}" DEBUG set +xv pipefail echo "TEST SUCCESSFUL" exit 0 From 2a5451a35c4b053ad926585d0f00012eaaeade0a Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 29 Sep 2022 15:32:21 +0800 Subject: [PATCH 25/29] Fix Go binding build error (#1535) --- language-bindings/go/wamr/module.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/language-bindings/go/wamr/module.go b/language-bindings/go/wamr/module.go index 9d6b7d94..13480b22 100644 --- a/language-bindings/go/wamr/module.go +++ b/language-bindings/go/wamr/module.go @@ -134,8 +134,7 @@ func (self *Module) SetWasiAddrPool(addrPool [][]byte) { } /* Set module's wasi domain lookup pool */ -func(self *Module) SetWasiNsLookupPool(nsLookupPool[][] byte) -{ +func(self *Module) SetWasiNsLookupPool(nsLookupPool [][]byte) { var nsLookupPoolPtr **C.char var nsLookupPoolSize C.uint @@ -144,4 +143,4 @@ func(self *Module) SetWasiNsLookupPool(nsLookupPool[][] byte) nsLookupPoolSize = C.uint(len(nsLookupPool)) } C.wasm_runtime_set_wasi_ns_lookup_pool(self.module, nsLookupPoolPtr, nsLookupPoolSize) -} \ No newline at end of file +} From dc2c6c75f5846581fd36bf4ea94e87c2647341ed Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Thu, 29 Sep 2022 11:16:16 +0100 Subject: [PATCH 26/29] Update socket API samples doc to cover UDP client/server and addr_resolve samples (#1538) Also fix installing `addr_resolve.wasm` example. Resolves #1534 --- samples/socket-api/CMakeLists.txt | 1 + samples/socket-api/README.md | 64 +++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/samples/socket-api/CMakeLists.txt b/samples/socket-api/CMakeLists.txt index 193eb264..fcf40cc5 100644 --- a/samples/socket-api/CMakeLists.txt +++ b/samples/socket-api/CMakeLists.txt @@ -87,6 +87,7 @@ ExternalProject_Add(wasm-app ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src BUILD_COMMAND ${CMAKE_COMMAND} --build . INSTALL_COMMAND ${CMAKE_COMMAND} -E copy + addr_resolve.wasm ${CMAKE_BINARY_DIR} tcp_client.wasm ${CMAKE_BINARY_DIR} tcp_server.wasm ${CMAKE_BINARY_DIR} send_recv.wasm ${CMAKE_BINARY_DIR} diff --git a/samples/socket-api/README.md b/samples/socket-api/README.md index 5260e851..2d22e3b2 100644 --- a/samples/socket-api/README.md +++ b/samples/socket-api/README.md @@ -18,14 +18,21 @@ cmake .. make ``` -`iwasm` and three Wasm modules, `tcp_server.wasm`, `tcp_client.wasm`, `send_recv.wasm` -will be generated. And their corresponding native version, `tcp_server`, -`tcp_client`, `send_recv` are generated too. +`iwasm` and the following Wasm modules (along with their corresponding native version) will be generated: + * `addr_resolve.wasm`, `addr_resolve` + * `send_recv.wasm`, `send_recv` + * `socket_opts.wasm`, `socket_opts` + * `tcp_client.wasm`, `tcp_client` + * `tcp_server.wasm`, `tcp_server` + * `udp_client.wasm`, `udp_client` + * `udp_server.wasm`, `udp_server` > Note that iwasm is built with libc-wasi and lib-pthread enabled. ## Run workload +### TCP client/server + Start the tcp server, which opens port 1234 and waits for clients to connect. ```bash @@ -82,6 +89,8 @@ Data: And mourns for us ``` +### Socket options + `socket_opts.wasm` shows an example of getting and setting various supported socket options ```bash $ ./iwasm ./socket_opts.wasm @@ -98,4 +107,53 @@ SO_RCVTIMEO tv_usec is expected [Client] Close sockets ``` +### Domain name server resolution + +`addr_resolve.wasm` demonstrates the usage of resolving a domain name +``` +$ ./iwasm --allow-resolve=*.com addr_resolve.wasm github.com +``` + +The command displays the host name and its corresponding IP address: +``` +Host: github.com +IPv4 address: 140.82.121.4 (TCP) +``` + +### UDP client/server + +Start the UDP server, which opens port 1234 and waits for clients to send a message. + +```bash +cd build +./iwasm --addr-pool=0.0.0.0/15 udp_server.wasm +``` + +Start the tcp client, which sends a message to the server and waits for the response. + +```bash +cd build +./iwasm --addr-pool=127.0.0.1/15 udp_client.wasm +``` + +The output of client is like: + +```bash +[Client] Create socket +[Client] Client send +[Client] Client receive +[Client] Buffer recieved: Hello from server +[Client] BYE +``` + +The output of the server is like: +``` +[Server] Create socket +[Server] Bind socket +[Server] Wait for clients to connect .. +[Server] received 17 bytes from 127.0.0.1:60927: Hello from client +``` + +## Documentation + Refer to [socket api document](../../doc/socket_api.md) for more details. From 3fad613ea2537c1b0a736026188b9900ec9fc654 Mon Sep 17 00:00:00 2001 From: dzobbe Date: Thu, 29 Sep 2022 14:52:11 +0200 Subject: [PATCH 27/29] Enable build wasi_socket_ext.c with both clang and clang++ (#1527) Enable to run WolfSSL into wasm and need some features from C++: https://github.com/JamesMenetrey/wolfssl-examples/tree/wasm/Wasm --- .../lib-socket/src/wasi/wasi_socket_ext.c | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) 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 index 79a59416..a2722086 100644 --- a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c +++ b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c @@ -6,8 +6,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -136,10 +136,12 @@ wasi_addr_to_sockaddr(const __wasi_addr_t *wasi_addr, int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - __wasi_addr_t wasi_addr = { 0 }; + __wasi_addr_t wasi_addr; __wasi_fd_t new_sockfd; __wasi_errno_t error; + memset(&wasi_addr, 0, sizeof(wasi_addr)); + error = __wasi_sock_accept(sockfd, 0, &new_sockfd); HANDLE_ERROR(error) @@ -152,9 +154,11 @@ accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { - __wasi_addr_t wasi_addr = { 0 }; + __wasi_addr_t wasi_addr; __wasi_errno_t error; + memset(&wasi_addr, 0, sizeof(wasi_addr)); + error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr); HANDLE_ERROR(error) @@ -167,9 +171,11 @@ bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { - __wasi_addr_t wasi_addr = { 0 }; + __wasi_addr_t wasi_addr; __wasi_errno_t error; + memset(&wasi_addr, 0, sizeof(wasi_addr)); + if (NULL == addr) { HANDLE_ERROR(__WASI_ERRNO_INVAL) } @@ -210,12 +216,13 @@ recvmsg(int sockfd, struct msghdr *msg, int flags) } // __wasi_ciovec_t -> struct iovec - if (!(ri_data = malloc(sizeof(__wasi_iovec_t) * msg->msg_iovlen))) { + if (!(ri_data = (__wasi_iovec_t *)malloc(sizeof(__wasi_iovec_t) + * msg->msg_iovlen))) { HANDLE_ERROR(__WASI_ERRNO_NOMEM) } for (i = 0; i < msg->msg_iovlen; i++) { - ri_data[i].buf = msg->msg_iov[i].iov_base; + ri_data[i].buf = (uint8_t *)msg->msg_iov[i].iov_base; ri_data[i].buf_len = msg->msg_iov[i].iov_len; } @@ -246,12 +253,13 @@ sendmsg(int sockfd, const struct msghdr *msg, int flags) } // struct iovec -> __wasi_ciovec_t - if (!(si_data = malloc(sizeof(__wasi_ciovec_t) * msg->msg_iovlen))) { + if (!(si_data = (__wasi_ciovec_t *)malloc(sizeof(__wasi_ciovec_t) + * msg->msg_iovlen))) { HANDLE_ERROR(__WASI_ERRNO_NOMEM) } for (i = 0; i < msg->msg_iovlen; i++) { - si_data[i].buf = msg->msg_iov[i].iov_base; + si_data[i].buf = (uint8_t *)msg->msg_iov[i].iov_base; si_data[i].buf_len = msg->msg_iov[i].iov_len; } @@ -269,7 +277,7 @@ sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { // Prepare input parameters. - __wasi_ciovec_t iov = { .buf = buf, .buf_len = len }; + __wasi_ciovec_t iov = { .buf = (uint8_t *)buf, .buf_len = len }; uint32_t so_datalen = 0; __wasi_addr_t wasi_addr; __wasi_errno_t error; @@ -297,7 +305,7 @@ recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { // Prepare input parameters. - __wasi_ciovec_t iov = { .buf = buf, .buf_len = len }; + __wasi_ciovec_t iov = { .buf = (uint8_t *)buf, .buf_len = len }; uint32_t so_datalen = 0; __wasi_addr_t wasi_addr; __wasi_errno_t error; @@ -363,9 +371,11 @@ socket(int domain, int type, int protocol) int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - __wasi_addr_t wasi_addr = { 0 }; + __wasi_addr_t wasi_addr; __wasi_errno_t error; + memset(&wasi_addr, 0, sizeof(wasi_addr)); + error = __wasi_sock_addr_local(sockfd, &wasi_addr); HANDLE_ERROR(error) @@ -378,9 +388,11 @@ getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { - __wasi_addr_t wasi_addr = { 0 }; + __wasi_addr_t wasi_addr; __wasi_errno_t error; + memset(&wasi_addr, 0, sizeof(wasi_addr)); + error = __wasi_sock_addr_remote(sockfd, &wasi_addr); HANDLE_ERROR(error) @@ -504,7 +516,8 @@ getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, return __WASI_ERRNO_SUCCESS; } - aibuf_res = calloc(1, addr_info_size * sizeof(struct aibuf)); + aibuf_res = + (struct aibuf *)calloc(1, addr_info_size * sizeof(struct aibuf)); if (!aibuf_res) { free(addr_info); HANDLE_ERROR(__WASI_ERRNO_NOMEM) @@ -750,58 +763,78 @@ set_sol_socket_option(int sockfd, int optname, const void *optval, switch (optname) { case SO_RCVTIMEO: + { assert(optlen == sizeof(struct timeval)); timeout_us = timeval_to_time_us(*(struct timeval *)optval); error = __wasi_sock_set_recv_timeout(sockfd, timeout_us); HANDLE_ERROR(error); return error; + } case SO_SNDTIMEO: + { assert(optlen == sizeof(struct timeval)); timeout_us = timeval_to_time_us(*(struct timeval *)optval); error = __wasi_sock_set_send_timeout(sockfd, timeout_us); HANDLE_ERROR(error); return error; + } case SO_SNDBUF: + { assert(optlen == sizeof(int)); error = __wasi_sock_set_send_buf_size(sockfd, *(size_t *)optval); HANDLE_ERROR(error); return error; + } case SO_RCVBUF: + { assert(optlen == sizeof(int)); error = __wasi_sock_set_recv_buf_size(sockfd, *(size_t *)optval); HANDLE_ERROR(error); return error; + } case SO_KEEPALIVE: + { assert(optlen == sizeof(int)); error = __wasi_sock_set_keep_alive(sockfd, *(bool *)optval); HANDLE_ERROR(error); return error; + } case SO_REUSEADDR: + { assert(optlen == sizeof(int)); error = __wasi_sock_set_reuse_addr(sockfd, *(bool *)optval); HANDLE_ERROR(error); return error; + } case SO_REUSEPORT: + { assert(optlen == sizeof(int)); error = __wasi_sock_set_reuse_port(sockfd, *(bool *)optval); HANDLE_ERROR(error); return error; + } case SO_LINGER: + { assert(optlen == sizeof(struct linger)); struct linger *linger_opt = ((struct linger *)optval); error = __wasi_sock_set_linger(sockfd, (bool)linger_opt->l_onoff, linger_opt->l_linger); HANDLE_ERROR(error); return error; + } case SO_BROADCAST: + { assert(optlen == sizeof(int)); error = __wasi_sock_set_broadcast(sockfd, *(bool *)optval); HANDLE_ERROR(error); return error; + } default: + { error = __WASI_ERRNO_NOTSUP; HANDLE_ERROR(error); return error; + } } } From 5b10d4e630b003708bf34d1669b139f8f544bf5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A4mes=20M=C3=A9n=C3=A9trey?= Date: Thu, 29 Sep 2022 16:44:57 +0200 Subject: [PATCH 28/29] socket: Explicit narrowing type cast and add missing static keywords (#1539) While compiling the file wasi_socket_ext.c with pedantic options (typically `-Wimplicit-int-conversion` and `-Wmissing-prototypes`), some warnings are raised. This PR addresses those warnings by adding missing static statements before functions and explicitly casting a narrowing conversion. And fix the error handling after calling getpeername. --- .../lib-socket/src/wasi/wasi_socket_ext.c | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) 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 index a2722086..22d51a7b 100644 --- a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c +++ b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c @@ -145,8 +145,9 @@ accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) error = __wasi_sock_accept(sockfd, 0, &new_sockfd); HANDLE_ERROR(error) - error = getpeername(new_sockfd, addr, addrlen); - HANDLE_ERROR(error) + if (getpeername(new_sockfd, addr, addrlen) == -1) { + return -1; + } return new_sockfd; } @@ -556,7 +557,7 @@ freeaddrinfo(struct addrinfo *res) free(res); } -struct timeval +static struct timeval time_us_to_timeval(uint64_t time_us) { struct timeval tv; @@ -565,13 +566,13 @@ time_us_to_timeval(uint64_t time_us) return tv; } -uint64_t +static uint64_t timeval_to_time_us(struct timeval tv) { return (tv.tv_sec * 1000000UL) + tv.tv_usec; } -int +static int get_sol_socket_option(int sockfd, int optname, void *__restrict optval, socklen_t *__restrict optlen) { @@ -638,7 +639,7 @@ get_sol_socket_option(int sockfd, int optname, void *__restrict optval, } } -int +static int get_ipproto_tcp_option(int sockfd, int optname, void *__restrict optval, socklen_t *__restrict optlen) { @@ -677,7 +678,7 @@ get_ipproto_tcp_option(int sockfd, int optname, void *__restrict optval, } } -int +static int get_ipproto_ip_option(int sockfd, int optname, void *__restrict optval, socklen_t *__restrict optlen) { @@ -707,7 +708,7 @@ get_ipproto_ip_option(int sockfd, int optname, void *__restrict optval, } } -int +static int get_ipproto_ipv6_option(int sockfd, int optname, void *__restrict optval, socklen_t *__restrict optlen) { @@ -754,7 +755,7 @@ getsockopt(int sockfd, int level, int optname, void *__restrict optval, } } -int +static int set_sol_socket_option(int sockfd, int optname, const void *optval, socklen_t optlen) { @@ -838,7 +839,7 @@ set_sol_socket_option(int sockfd, int optname, const void *optval, } } -int +static int set_ipproto_tcp_option(int sockfd, int optname, const void *optval, socklen_t optlen) { @@ -878,7 +879,7 @@ set_ipproto_tcp_option(int sockfd, int optname, const void *optval, } } -int +static int set_ipproto_ip_option(int sockfd, int optname, const void *optval, socklen_t optlen) { @@ -931,7 +932,7 @@ set_ipproto_ip_option(int sockfd, int optname, const void *optval, } } -int +static int set_ipproto_ipv6_option(int sockfd, int optname, const void *optval, socklen_t optlen) { From 4489c3da2bef6a5f9a8cdfb6c0100ee5dea3970e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A4mes=20M=C3=A9n=C3=A9trey?= Date: Thu, 29 Sep 2022 21:02:22 +0200 Subject: [PATCH 29/29] hash map: Fix a wrongly named parameter and enhance the docs (#1540) --- core/shared/utils/bh_hashmap.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/shared/utils/bh_hashmap.h b/core/shared/utils/bh_hashmap.h index ca61ae41..018f0513 100644 --- a/core/shared/utils/bh_hashmap.h +++ b/core/shared/utils/bh_hashmap.h @@ -25,12 +25,12 @@ typedef uint32 (*HashFunc)(const void *key); typedef bool (*KeyEqualFunc)(void *key1, void *key2); /* Key destroy function: to destroy the key, auto called - when an hash element is removed. */ + for each key when the hash map is destroyed. */ typedef void (*KeyDestroyFunc)(void *key); /* Value destroy function: to destroy the value, auto called - when an hash element is removed. */ -typedef void (*ValueDestroyFunc)(void *key); + for each value when the hash map is destroyed. */ +typedef void (*ValueDestroyFunc)(void *value); /* traverse callback function: auto called when traverse every hash element */ @@ -44,10 +44,10 @@ typedef void (*TraverseCallbackFunc)(void *key, void *value, void *user_data); * @param hash_func hash function of the key, must be specified * @param key_equal_func key equal function, check whether two keys * are equal, must be specified - * @param key_destroy_func key destroy function, called when an hash element - * is removed if it is not NULL - * @param value_destroy_func value destroy function, called when an hash - * element is removed if it is not NULL + * @param key_destroy_func key destroy function, called for each key if not NULL + * when the hash map is destroyed + * @param value_destroy_func value destroy function, called for each value if + * not NULL when the hash map is destroyed * * @return the hash map created, NULL if failed */