From 78b5c5b484697ced35e320fe7d6e47963b138a17 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Thu, 22 Sep 2022 21:46:14 +0800 Subject: [PATCH] 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; +}