Browse Source

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 <mkolny@amazon.com>
Co-authored-by: Marcin Kolny <marcin.kolny@gmail.com>
Co-authored-by: Callum Macmillan <callumimacmillan@gmail.com>
Wenyong Huang 3 years ago
parent
commit
78b5c5b484
31 changed files with 6345 additions and 470 deletions
  1. 5 3
      core/iwasm/aot/aot_runtime.c
  2. 95 52
      core/iwasm/common/wasm_runtime_common.c
  3. 8 0
      core/iwasm/common/wasm_runtime_common.h
  4. 4 0
      core/iwasm/include/wasm_export.h
  5. 2 0
      core/iwasm/interpreter/wasm.h
  6. 5 3
      core/iwasm/interpreter/wasm_runtime.c
  7. 1 1
      core/iwasm/libraries/debug-engine/gdbserver.c
  8. 595 32
      core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h
  9. 752 40
      core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c
  10. 919 150
      core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c
  11. 366 2
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h
  12. 573 51
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c
  13. 6 2
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h
  14. 815 23
      core/shared/platform/common/posix/posix_socket.c
  15. 558 5
      core/shared/platform/include/platform_api_extension.h
  16. 463 47
      core/shared/platform/linux-sgx/sgx_socket.c
  17. 11 1
      core/shared/platform/linux-sgx/sgx_socket.h
  18. 385 8
      core/shared/platform/windows/win_socket.c
  19. 8 0
      doc/socket_api.md
  20. 13 0
      language-bindings/go/wamr/module.go
  21. 50 29
      product-mini/platforms/posix/main.c
  22. 11 0
      samples/socket-api/CMakeLists.txt
  23. 16 0
      samples/socket-api/README.md
  24. 4 0
      samples/socket-api/wasm-src/CMakeLists.txt
  25. 69 0
      samples/socket-api/wasm-src/addr_resolve.c
  26. 262 0
      samples/socket-api/wasm-src/socket_opts.c
  27. 48 0
      samples/socket-api/wasm-src/socket_utils.h
  28. 55 11
      samples/socket-api/wasm-src/tcp_client.c
  29. 44 10
      samples/socket-api/wasm-src/tcp_server.c
  30. 82 0
      samples/socket-api/wasm-src/udp_client.c
  31. 120 0
      samples/socket-api/wasm-src/udp_server.c

+ 5 - 3
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

+ 95 - 52
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);
     }
 }

+ 8 - 0
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

+ 4 - 0
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.
  *

+ 2 - 0
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];

+ 5 - 3
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;
         }
     }

+ 1 - 1
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;
     }

+ 595 - 32
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 <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -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;
  * <sys/socket.h>
  * <sys/types.h>
  */
+#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, (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_send_buf_size((int32_t)fd);
+        __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
+#endif

+ 752 - 40
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;
-
-    error =
-        __wasi_sock_addr_remote(fd, (uint8_t *)&wasi_addr, sizeof(wasi_addr));
-    if (__WASI_ERRNO_SUCCESS != error) {
-        return error;
-    }
-
-    if (IPv4 == wasi_addr.kind) {
-        struct sockaddr_in sock_addr_in = { 0 };
-
-        sock_addr_in.sin_family = AF_INET;
-        sock_addr_in.sin_addr.s_addr = (wasi_addr.addr.ip4.addr.n3 << 24)
-                                       | (wasi_addr.addr.ip4.addr.n2 << 16)
-                                       | (wasi_addr.addr.ip4.addr.n1 << 8)
-                                       | wasi_addr.addr.ip4.addr.n0;
-        sock_addr_in.sin_port = htons(wasi_addr.addr.ip4.port);
-        memcpy(sock_addr, &sock_addr_in, sizeof(sock_addr_in));
-
-        *addrlen = sizeof(sock_addr_in);
-    }
-    else if (IPv6 == wasi_addr.kind) {
-        // TODO: IPV6
-        return __WASI_ERRNO_AFNOSUPPORT;
-    }
-    else {
-        return __WASI_ERRNO_AFNOSUPPORT;
+    switch (wasi_addr->kind) {
+        case IPv4:
+        {
+            struct sockaddr_in sock_addr_in = { 0 };
+            uint32_t s_addr;
+
+            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;
     }
-
     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;
+    }
+}

File diff suppressed because it is too large
+ 919 - 150
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c


+ 366 - 2
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 <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -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__));
 

+ 573 - 51
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 inline size_t
+min(size_t a, size_t b)
+{
+    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, const char *addr)
+compare_address(const struct addr_pool *addr_pool_entry,
+                bh_ip_addr_buffer_t *target)
 {
-    /* host order */
-    uint32 target;
-    uint32 address = addr_pool_entry->addr;
-    /* 0.0.0.0 means any address */
-    if (0 == address) {
-        return true;
+    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;
 
-    if (os_socket_inet_network(addr, &target) != BHT_OK) {
-        return false;
+    /* IPv4 0.0.0.0 or IPv6 :: means any address */
+    if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) {
+        return true;
     }
 
-    const uint32 max_mask_value = 32;
-    /* no support for invalid mask values */
-    if (addr_pool_entry->mask > max_mask_value) {
+    /* No support for invalid mask value */
+    if (addr_pool_entry->mask > max_addr_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);
+    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;
+        }
     }
 
-    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;
+}

+ 6 - 2
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;
 };
 

+ 815 - 23
core/shared/platform/common/posix/posix_socket.c

@@ -7,29 +7,123 @@
 #include "platform_api_extension.h"
 
 #include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
 
-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);
+}

+ 558 - 5
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
+ *
+ * @param cp a string in IPv4 numbers-and-dots notation or IPv6
+ * numbers-and-colons notation
  *
- * @return On success, the converted address is  returned.
+ * @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
 }

+ 463 - 47
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,58 +132,97 @@ 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;
+    if (c - '0' < 10)
+        return c - '0';
+    c |= 32;
+    if (c - 'a' < 6)
+        return c - 'a' + 10;
+    return -1;
+}
 
-    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;
+/* Coming from musl, under MIT license */
+static int
+inet_pton(int af, const char *restrict s, void *restrict a0)
+{
+    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;
     }
-    if (i == 4)
+    else if (af != AF_INET6) {
+        errno = EAFNOSUPPORT;
+        return -1;
+    }
+
+    if (*s == ':' && *++s != ':')
         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)
+
+    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;
-        d[i] = a[i];
+        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;
 }
 
-/* Coming from musl, under MIT license */
 static int
 inet_addr(const char *p)
 {
     struct in_addr a;
-    if (!__inet_aton(p, &a))
+    if (!inet_pton(AF_INET, p, &a))
         return -1;
     return a.s_addr;
 }
-
-static int
-inet_network(const char *p)
-{
-    return ntohl(inet_addr(p));
-}
 /** In-enclave implementation of POSIX functions end **/
 
 static int
@@ -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

+ 11 - 1
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);
 

+ 385 - 8
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 {
+        errno = ENOSYS;
+        return BHT_ERROR;
+    }
+
+    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;
@@ -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;
-}
+}
+
+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;
+}

+ 8 - 0
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

+ 13 - 0
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)
+}

+ 50 - 29
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=<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=<dir>            Grant wasi access to the given host directories\n");
-    printf("                         to the program, for example:\n");
-    printf("                           --dir=<dir1> --dir=<dir2>\n");
-    printf("  --addr-pool=<addrs>    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=<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=<dir>              Grant wasi access to the given host directories\n");
+    printf("                           to the program, for example:\n");
+    printf("                             --dir=<dir1> --dir=<dir2>\n");
+    printf("  --addr-pool=<addrs>      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=<domain> 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=<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=<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=<path>   Indicate a module search path. default is current\n"
-           "                         directory('./')\n");
+    printf("  --module-path=<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 */

+ 11 - 0
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
 ############################################

+ 16 - 0
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.

+ 4 - 0
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)

+ 69 - 0
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 <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __wasi__
+#include <wasi_socket_ext.h>
+#else
+#include <netdb.h>
+#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]);
+}

+ 262 - 0
samples/socket-api/wasm-src/socket_opts.c

@@ -0,0 +1,262 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/tcp.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#ifdef __wasi__
+#include <wasi_socket_ext.h>
+#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;
+}

+ 48 - 0
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 <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+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 */

+ 55 - 11
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 <arpa/inet.h>
 #include <netinet/in.h>
@@ -14,34 +15,77 @@
 #include <wasi_socket_ext.h>
 #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,

+ 44 - 10
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 <arpa/inet.h>
 #include <netinet/in.h>
 #include <pthread.h>
@@ -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");

+ 82 - 0
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 <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#ifdef __wasi__
+#include <wasi_socket_ext.h>
+#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;
+}

+ 120 - 0
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 <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#ifdef __wasi__
+#include <wasi_socket_ext.h>
+#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;
+}

Some files were not shown because too many files changed in this diff