ソースを参照

Implement part of Berkeley Socket API for libc-wasi (#1036)

Refer to [Networking API design](https://github.com/WebAssembly/WASI/issues/370)
and [feat(socket): berkeley socket API v2](https://github.com/WebAssembly/WASI/pull/459):

- Support the socket API of synchronous mode, including `socket/bind/listen/accept/send/recv/close/shutdown`,
    the asynchronous mode isn't supported yet.
- Support adding `--addr-pool=<pool1,pool2,..>` argument for command line to identify the valid ip address range
- Add socket-api sample and update the document
Wenyong Huang 3 年 前
コミット
9c87a1ee17
28 ファイル変更2204 行追加207 行削除
  1. 2 0
      README.md
  2. 1 0
      core/iwasm/aot/aot_runtime.c
  3. 74 7
      core/iwasm/common/wasm_runtime_common.c
  4. 8 3
      core/iwasm/common/wasm_runtime_common.h
  5. 4 0
      core/iwasm/include/wasm_export.h
  6. 3 0
      core/iwasm/interpreter/wasm.h
  7. 1 0
      core/iwasm/interpreter/wasm_runtime.c
  8. 410 0
      core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h
  9. 9 0
      core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake
  10. 180 0
      core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c
  11. 254 63
      core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c
  12. 27 22
      core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h
  13. 155 40
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h
  14. 331 64
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c
  15. 16 0
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h
  16. 16 5
      core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h
  17. 37 0
      core/shared/platform/common/posix/posix_socket.c
  18. 23 0
      core/shared/platform/include/platform_api_extension.h
  19. 68 0
      core/shared/platform/linux-sgx/sgx_socket.c
  20. 10 0
      core/shared/platform/windows/win_socket.c
  21. 66 0
      doc/socket_api.md
  22. 30 3
      product-mini/platforms/posix/main.c
  23. 162 0
      samples/socket-api/CMakeLists.txt
  24. 57 0
      samples/socket-api/README.md
  25. 80 0
      samples/socket-api/wasm-src/CMakeLists.txt
  26. 0 0
      samples/socket-api/wasm-src/inc/.gitkeep
  27. 62 0
      samples/socket-api/wasm-src/tcp_client.c
  28. 118 0
      samples/socket-api/wasm-src/tcp_server.c

+ 2 - 0
README.md

@@ -42,6 +42,7 @@ iwasm VM core
 - [Source debugging support](./doc/source_debugging.md), ref to [document](./doc/source_debugging.md)
 - [WAMR-IDE (Experimental)](./test-tools/wamr-ide) to develop WebAssembly applications with build, run and debug support, ref to [document](./test-tools/wamr-ide)
 - [XIP (Execution In Place) support](./doc/xip.md), ref to [document](./doc/xip.md)
+- [Berkeley/Posix Socket support](./doc/socket_api.md), ref to [document](./doc/socket_api.md) and [sample](./samples/socket-api)
 
 ### WASM post-MVP features
 - [wasm-c-api](https://github.com/WebAssembly/wasm-c-api), ref to [document](doc/wasm_c_api.md) and [sample](samples/wasm-c-api)
@@ -153,6 +154,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a
 - **[multi-module](./samples/multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/).
 - **[ref-types](./samples/ref-types)**: Demonstrating how to call wasm functions with argument of externref type introduced by [reference types proposal](https://github.com/WebAssembly/reference-types).
 - **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's.
+- **[socket-api](./samples/socket-api/README.md)**: Demonstrating how to run wasm tcp server and tcp client applications, and how they communicate with each other.
 - **[workload](./samples/workload/README.md)**: Demonstrating how to build and run some complex workloads, e.g. tensorflow-lite, XNNPACK, wasm-av1, meshoptimizer and bwa.
 
 

+ 1 - 0
core/iwasm/aot/aot_runtime.c

@@ -1020,6 +1020,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
                 module->wasi_args.dir_list, module->wasi_args.dir_count,
                 module->wasi_args.map_dir_list, module->wasi_args.map_dir_count,
                 module->wasi_args.env, module->wasi_args.env_count,
+                module->wasi_args.addr_pool, module->wasi_args.addr_count,
                 module->wasi_args.argv, module->wasi_args.argc,
                 module->wasi_args.stdio[0], module->wasi_args.stdio[1],
                 module->wasi_args.stdio[2], error_buf, error_buf_size))

+ 74 - 7
core/iwasm/common/wasm_runtime_common.c

@@ -2191,14 +2191,36 @@ wasm_runtime_set_wasi_args(WASMModuleCommon *module, const char *dir_list[],
                                   argc, -1, -1, -1);
 }
 
+void
+wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
+                                uint32 addr_pool_size)
+{
+    WASIArguments *wasi_args = NULL;
+
+#if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0
+    if (module->module_type == Wasm_Module_Bytecode)
+        wasi_args = &((WASMModule *)module)->wasi_args;
+#endif
+#if WASM_ENABLE_AOT != 0
+    if (module->module_type == Wasm_Module_AoT)
+        wasi_args = &((AOTModule *)module)->wasi_args;
+#endif
+
+    if (wasi_args) {
+        wasi_args->addr_pool = addr_pool;
+        wasi_args->addr_count = addr_pool_size;
+    }
+}
+
 #if WASM_ENABLE_UVWASI == 0
 bool
 wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *dir_list[], uint32 dir_count,
                        const char *map_dir_list[], uint32 map_dir_count,
-                       const char *env[], uint32 env_count, char *argv[],
-                       uint32 argc, int stdinfd, int stdoutfd, int stderrfd,
-                       char *error_buf, uint32 error_buf_size)
+                       const char *env[], uint32 env_count,
+                       const char *addr_pool[], uint32 addr_pool_size,
+                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
+                       int stderrfd, char *error_buf, uint32 error_buf_size)
 {
     WASIContext *wasi_ctx;
     char *argv_buf = NULL;
@@ -2210,8 +2232,10 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
     struct fd_table *curfds = NULL;
     struct fd_prestats *prestats = NULL;
     struct argv_environ_values *argv_environ = NULL;
+    struct addr_pool *apool = NULL;
     bool fd_table_inited = false, fd_prestats_inited = false;
     bool argv_environ_inited = false;
+    bool addr_pool_inited = false;
     __wasi_fd_t wasm_fd = 3;
     int32 raw_fd;
     char *path, resolved_path[PATH_MAX];
@@ -2285,7 +2309,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
     if (!(curfds = wasm_runtime_malloc(sizeof(struct fd_table)))
         || !(prestats = wasm_runtime_malloc(sizeof(struct fd_prestats)))
         || !(argv_environ =
-                 wasm_runtime_malloc(sizeof(struct argv_environ_values)))) {
+                 wasm_runtime_malloc(sizeof(struct argv_environ_values)))
+        || !(apool = wasm_runtime_malloc(sizeof(struct addr_pool)))) {
         set_error_buf(error_buf, error_buf_size,
                       "Init wasi environment failed: allocate memory failed");
         goto fail;
@@ -2316,6 +2341,14 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
     }
     argv_environ_inited = true;
 
+    if (!addr_pool_init(apool)) {
+        set_error_buf(error_buf, error_buf_size,
+                      "Init wasi environment failed: "
+                      "init the address pool failed");
+        goto fail;
+    }
+    addr_pool_inited = true;
+
     /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */
     if (!fd_table_insert_existing(curfds, 0, (stdinfd != -1) ? stdinfd : 0)
         || !fd_table_insert_existing(curfds, 1, (stdoutfd != -1) ? stdoutfd : 1)
@@ -2350,9 +2383,34 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
         fd_prestats_insert(prestats, dir_list[i], wasm_fd);
     }
 
+    /* addr_pool(textual) -> apool */
+    for (i = 0; i < addr_pool_size; i++) {
+        char *cp, *address, *mask;
+        bool ret = false;
+
+        cp = bh_strdup(addr_pool[i]);
+        if (!cp) {
+            set_error_buf(error_buf, error_buf_size,
+                          "Init wasi environment failed: copy address failed");
+            goto fail;
+        }
+
+        address = strtok(cp, "/");
+        mask = strtok(NULL, "/");
+
+        ret = addr_pool_insert(apool, address, (uint8)(atoi(mask)));
+        wasm_runtime_free(cp);
+        if (!ret) {
+            set_error_buf(error_buf, error_buf_size,
+                          "Init wasi environment failed: store address failed");
+            goto fail;
+        }
+    }
+
     wasi_ctx->curfds = curfds;
     wasi_ctx->prestats = prestats;
     wasi_ctx->argv_environ = argv_environ;
+    wasi_ctx->addr_pool = apool;
     wasi_ctx->argv_buf = argv_buf;
     wasi_ctx->argv_list = argv_list;
     wasi_ctx->env_buf = env_buf;
@@ -2367,12 +2425,16 @@ fail:
         fd_prestats_destroy(prestats);
     if (fd_table_inited)
         fd_table_destroy(curfds);
+    if (addr_pool_inited)
+        addr_pool_destroy(apool);
     if (curfds)
         wasm_runtime_free(curfds);
     if (prestats)
         wasm_runtime_free(prestats);
     if (argv_environ)
         wasm_runtime_free(argv_environ);
+    if (apool)
+        wasm_runtime_free(apool);
     if (argv_buf)
         wasm_runtime_free(argv_buf);
     if (argv_list)
@@ -2430,9 +2492,10 @@ bool
 wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *dir_list[], uint32 dir_count,
                        const char *map_dir_list[], uint32 map_dir_count,
-                       const char *env[], uint32 env_count, char *argv[],
-                       uint32 argc, int stdinfd, int stdoutfd, int stderrfd,
-                       char *error_buf, uint32 error_buf_size)
+                       const char *env[], uint32 env_count,
+                       const char *addr_pool[], uint32 addr_pool_size,
+                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
+                       int stderrfd, char *error_buf, uint32 error_buf_size)
 {
     uvwasi_t *uvwasi = NULL;
     uvwasi_options_t init_options;
@@ -2595,6 +2658,10 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst)
             fd_prestats_destroy(wasi_ctx->prestats);
             wasm_runtime_free(wasi_ctx->prestats);
         }
+        if (wasi_ctx->addr_pool) {
+            addr_pool_destroy(wasi_ctx->addr_pool);
+            wasm_runtime_free(wasi_ctx->addr_pool);
+        }
         if (wasi_ctx->argv_buf)
             wasm_runtime_free(wasi_ctx->argv_buf);
         if (wasi_ctx->argv_list)

+ 8 - 3
core/iwasm/common/wasm_runtime_common.h

@@ -352,6 +352,7 @@ typedef struct WASIContext {
     struct fd_table *curfds;
     struct fd_prestats *prestats;
     struct argv_environ_values *argv_environ;
+    struct addr_pool *addr_pool;
     char *argv_buf;
     char **argv_list;
     char *env_buf;
@@ -712,9 +713,10 @@ bool
 wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
                        const char *dir_list[], uint32 dir_count,
                        const char *map_dir_list[], uint32 map_dir_count,
-                       const char *env[], uint32 env_count, char *argv[],
-                       uint32 argc, int stdinfd, int stdoutfd, int stderrfd,
-                       char *error_buf, uint32 error_buf_size);
+                       const char *env[], uint32 env_count,
+                       const char *addr_pool[], uint32 addr_pool_size,
+                       char *argv[], uint32 argc, int stdinfd, int stdoutfd,
+                       int stderrfd, char *error_buf, uint32 error_buf_size);
 
 void
 wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst);
@@ -726,6 +728,9 @@ wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst,
 WASIContext *
 wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst);
 
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
+                                uint32 addr_pool_size);
 #endif /* end of WASM_ENABLE_LIBC_WASI */
 
 #if WASM_ENABLE_REF_TYPES != 0

+ 4 - 0
core/iwasm/include/wasm_export.h

@@ -348,6 +348,10 @@ wasm_runtime_set_wasi_args(wasm_module_t module,
                            const char *env[], uint32_t env_count,
                            char *argv[], int argc);
 
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
+                                uint32_t addr_pool_size);
+
 /**
  * Instantiate a WASM module.
  *

+ 3 - 0
core/iwasm/interpreter/wasm.h

@@ -305,6 +305,9 @@ typedef struct WASIArguments {
     uint32 map_dir_count;
     const char **env;
     uint32 env_count;
+    /* in CIDR noation */
+    const char **addr_pool;
+    uint32 addr_count;
     char **argv;
     uint32 argc;
     int stdio[3];

+ 1 - 0
core/iwasm/interpreter/wasm_runtime.c

@@ -1522,6 +1522,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
                 module->wasi_args.dir_list, module->wasi_args.dir_count,
                 module->wasi_args.map_dir_list, module->wasi_args.map_dir_count,
                 module->wasi_args.env, module->wasi_args.env_count,
+                module->wasi_args.addr_pool, module->wasi_args.addr_count,
                 module->wasi_args.argv, module->wasi_args.argc,
                 module->wasi_args.stdio[0], module->wasi_args.stdio[1],
                 module->wasi_args.stdio[2], error_buf, error_buf_size)) {

+ 410 - 0
core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h

@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _WASI_SOCKET_EXT_H_
+#define _WASI_SOCKET_EXT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*Be a part of <wasi/api.h>*/
+
+typedef enum {
+    SOCKET_DGRAM = 0,
+    SOCKET_STREAM,
+} __wasi_sock_type_t;
+
+typedef uint16_t __wasi_ip_port_t;
+
+typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t;
+
+/* n0.n1.n2.n3 */
+typedef struct __wasi_addr_ip4_t {
+    uint8_t n0;
+    uint8_t n1;
+    uint8_t n2;
+    uint8_t n3;
+} __wasi_addr_ip4_t;
+
+typedef struct __wasi_addr_ip4_port_t {
+    __wasi_addr_ip4_t addr;
+    __wasi_ip_port_t port;
+} __wasi_addr_ip4_port_t;
+
+typedef struct __wasi_addr_ip6_t {
+    uint16_t n0;
+    uint16_t n1;
+    uint16_t n2;
+    uint16_t n3;
+    uint16_t h0;
+    uint16_t h1;
+    uint16_t h2;
+    uint16_t h3;
+} __wasi_addr_ip6_t;
+
+typedef struct __wasi_addr_ip6_port_t {
+    __wasi_addr_ip6_t addr;
+    __wasi_ip_port_t port;
+} __wasi_addr_ip6_port_t;
+
+typedef struct __wasi_addr_t {
+    __wasi_addr_type_t kind;
+    union {
+        __wasi_addr_ip4_port_t ip4;
+        __wasi_addr_ip6_port_t ip6;
+    } addr;
+} __wasi_addr_t;
+
+typedef enum { INET4 = 0, INET6 } __wasi_address_family_t;
+
+#ifdef __wasi__
+/**
+ * Reimplement below POSIX APIs with __wasi_sock_XXX functions.
+ *
+ * Keep sync with
+ * <sys/socket.h>
+ * <sys/types.h>
+ */
+
+int
+accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+
+int
+bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+int
+connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+int
+listen(int sockfd, int backlog);
+
+int
+socket(int domain, int type, int protocol);
+#endif
+
+/**
+ * Accept a connection on a socket
+ * Note: This is similar to `accept`
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_accept(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_accept")));
+
+static inline __wasi_errno_t
+__wasi_sock_accept(__wasi_fd_t fd, __wasi_fd_t *fd_new)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_accept(
+        (int32_t)fd, (int32_t)fd_new);
+}
+
+/**
+ * Returns the local address to which the socket is bound.
+ *
+ * Note: This is similar to `getsockname` in POSIX
+ *
+ * When successful, the contents of the output buffer consist of an IP address,
+ * either IP4 or IP6.
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1,
+                                                  int32_t arg2)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_addr_local")));
+
+static inline __wasi_errno_t
+__wasi_sock_addr_local(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_local(
+        (int32_t)fd, (int32_t)buf, (int32_t)buf_len);
+}
+
+/**
+ * Returns the remote address to which the socket is connected to.
+ *
+ * Note: This is similar to `getpeername` in POSIX
+ *
+ * When successful, the contents of the output buffer consist of an IP address,
+ * either IP4 or IP6.
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1,
+                                                   int32_t arg2)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_addr_remote")));
+
+static inline __wasi_errno_t
+__wasi_sock_addr_remote(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_remote(
+        (int32_t)fd, (int32_t)buf, (int32_t)buf_len);
+}
+
+/**
+ * Resolves a hostname and a port to one or more IP addresses. Port is optional
+ * and you can pass 0 (zero) in most cases, it is used a hint for protocol.
+ *
+ * Note: This is similar to `getaddrinfo` in POSIX
+ *
+ * When successful, the contents of the output buffer consist of a sequence of
+ * IPv4 and/or IPv6 addresses. Each address entry consists of a addr_t object.
+ *
+ * This function fills the output buffer as much as possible, potentially
+ * truncating the last address entry. It is advisable that the buffer is
+ */
+int32_t
+__imported_wasi_snapshot_preview1_addr_resolve(int32_t arg0, int32_t arg1,
+                                               int32_t arg2, int32_t arg3,
+                                               int32_t arg4)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("addr_resolve")));
+
+static inline __wasi_errno_t
+__wasi_addr_resolve(__wasi_fd_t fd, const char *host, __wasi_ip_port_t port,
+                    uint8_t *buf, __wasi_size_t size)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_addr_resolve(
+        (int32_t)fd, (int32_t)host, (int32_t)port, (int32_t)buf, (int32_t)size);
+}
+
+/**
+ * Bind a socket
+ * Note: This is similar to `bind` in POSIX using PF_INET
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_bind(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_bind")));
+
+static inline __wasi_errno_t
+__wasi_sock_bind(__wasi_fd_t fd, __wasi_addr_t *addr)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_bind(
+        (int32_t)fd, (int32_t)addr);
+}
+
+/**
+ * Close a socket (this is an alias for `fd_close`)
+ * Note: This is similar to `close` in POSIX.
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_close(int32_t arg0)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_close")));
+
+static inline __wasi_errno_t
+__wasi_sock_close(__wasi_fd_t fd)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_close(
+        (int32_t)fd);
+}
+
+/**
+ * Initiate a connection on a socket to the specified address
+ * Note: This is similar to `connect` in POSIX
+ */
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_connect(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_connect")));
+
+static inline __wasi_errno_t
+__wasi_sock_connect(__wasi_fd_t fd, __wasi_addr_t *addr)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_connect(
+        (int32_t)fd, (int32_t)addr);
+}
+/**
+ * Retrieve the size of the receive buffer
+ * Note: This is similar to `getsockopt` in POSIX for SO_RCVBUF
+ */
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_recv_buf_size(int32_t arg0,
+                                                         int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_recv_buf_size")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_recv_buf_size(__wasi_fd_t fd, __wasi_size_t *size)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_recv_buf_size((int32_t)fd,
+                                                                 (int32_t)size);
+}
+/**
+ * Retrieve status of address reuse on a socket
+ * Note: This is similar to `getsockopt` in POSIX for SO_REUSEADDR
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_reuse_addr(int32_t arg0,
+                                                      int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_reuse_addr")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_reuse_addr(__wasi_fd_t fd, uint8_t *reuse)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_reuse_addr((int32_t)fd,
+                                                              (int32_t)reuse);
+}
+
+/**
+ * Retrieve status of port reuse on a socket
+ * Note: This is similar to `getsockopt` in POSIX for SO_REUSEPORT
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_reuse_port(int32_t arg0,
+                                                      int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_reuse_port")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_reuse_port(__wasi_fd_t fd, int8_t *reuse)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_reuse_port((int32_t)fd,
+                                                              (int32_t)reuse);
+}
+
+/**
+ * Retrieve the size of the send buffer
+ * Note: This is similar to `getsockopt` in POSIX for SO_SNDBUF
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_send_buf_size(int32_t arg0,
+                                                         int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_send_buf_size")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_send_buf_size(__wasi_fd_t fd, __wasi_size_t *size)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_send_buf_size((int32_t)fd,
+                                                                 (int32_t)size);
+}
+
+/**
+ * Listen for connections on a socket
+ * Note: This is similar to `listen`
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_listen(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_listen")));
+
+static inline __wasi_errno_t
+__wasi_sock_listen(__wasi_fd_t fd, __wasi_size_t backlog)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_listen(
+        (int32_t)fd, (int32_t)backlog);
+}
+
+/**
+ * Open a socket
+
+ * The first argument to this function is a handle to an
+ * address pool. The address pool determines what actions can
+ * be performed and at which addresses they can be performed to.
+
+ * The address pool cannot be re-assigned. You will need to close
+ * the socket and open a new one to use a different address pool.
+
+ * Note: This is similar to `socket` in POSIX using PF_INET
+ */
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_open(int32_t arg0, int32_t arg1,
+                                            int32_t arg2, int32_t arg3)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_open")));
+
+static inline __wasi_errno_t
+__wasi_sock_open(__wasi_fd_t fd, __wasi_address_family_t af,
+                 __wasi_sock_type_t socktype, __wasi_fd_t *sockfd)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_open(
+        (int32_t)fd, (int32_t)af, (int32_t)socktype, (int32_t)sockfd);
+}
+
+/**
+ * Set size of receive buffer
+ * Note: This is similar to `setsockopt` in POSIX for SO_RCVBUF
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_recv_buf_size(int32_t arg0,
+                                                         int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_recv_buf_size")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_recv_buf_size(__wasi_fd_t fd, __wasi_size_t size)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_recv_buf_size((int32_t)fd,
+                                                                 (int32_t)size);
+}
+
+/**
+ * Enable/disable address reuse on a socket
+ * Note: This is similar to `setsockopt` in POSIX for SO_REUSEADDR
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_reuse_addr(int32_t arg0,
+                                                      int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_reuse_addr")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_reuse_addr(__wasi_fd_t fd, uint8_t reuse)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_reuse_addr((int32_t)fd,
+                                                              (int32_t)reuse);
+}
+
+/**
+ * Enable port reuse on a socket
+ * Note: This is similar to `setsockopt` in POSIX for SO_REUSEPORT
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_reuse_port(int32_t arg0,
+                                                      int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_reuse_port")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_reuse_port(__wasi_fd_t fd, uint8_t reuse)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_reuse_port((int32_t)fd,
+                                                              (int32_t)reuse);
+}
+
+/**
+ * Set size of send buffer
+ * Note: This is similar to `setsockopt` in POSIX for SO_SNDBUF
+ */
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_send_buf_size(int32_t arg0)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_send_buf_size")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_send_buf_size(__wasi_fd_t fd)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_send_buf_size((int32_t)fd);
+}
+
+/**
+ * TODO: modify recv() and send()
+ * since don't want to re-compile the wasi-libc,
+ * we tend to keep original implentations of recv() and send().
+ */
+#endif

+ 9 - 0
core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake

@@ -0,0 +1,9 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required (VERSION 2.8...3.16)
+
+project(socket_wasi_ext)
+
+add_library(${PROJECT_NAME} STATIC ${CMAKE_CURRENT_LIST_DIR}/src/wasi/wasi_socket_ext.c)
+target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/inc/)

+ 180 - 0
core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c

@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <wasi/api.h>
+#include <wasi_socket_ext.h>
+
+#define HANDLE_ERROR(error)              \
+    if (error != __WASI_ERRNO_SUCCESS) { \
+        errno = error;                   \
+        return -1;                       \
+    }
+
+/* addr_num and port are in network order */
+static void
+ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out)
+{
+    out->kind = IPv4;
+    out->addr.ip4.port = ntohs(port);
+    out->addr.ip4.addr.n3 = (addr_num & 0xFF000000) >> 24;
+    out->addr.ip4.addr.n2 = (addr_num & 0x00FF0000) >> 16;
+    out->addr.ip4.addr.n1 = (addr_num & 0x0000FF00) >> 8;
+    out->addr.ip4.addr.n0 = (addr_num & 0x000000FF);
+}
+
+static __wasi_errno_t
+sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen,
+                      __wasi_addr_t *wasi_addr)
+{
+    __wasi_errno_t ret = __WASI_ERRNO_SUCCESS;
+    if (AF_INET == sock_addr->sa_family) {
+        assert(sizeof(struct sockaddr_in) == addrlen);
+
+        ipv4_addr_to_wasi_addr(
+            ((struct sockaddr_in *)sock_addr)->sin_addr.s_addr,
+            ((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr);
+    }
+    else if (AF_INET6 == sock_addr->sa_family) {
+        // TODO: IPV6
+        ret = __WASI_ERRNO_AFNOSUPPORT;
+    }
+    else {
+        ret = __WASI_ERRNO_AFNOSUPPORT;
+    }
+
+    return ret;
+}
+
+static __wasi_errno_t
+sock_addr_remote(__wasi_fd_t fd, struct sockaddr *sock_addr, socklen_t *addrlen)
+{
+    __wasi_addr_t wasi_addr = { 0 };
+    __wasi_errno_t error;
+
+    error =
+        __wasi_sock_addr_remote(fd, (uint8_t *)&wasi_addr, sizeof(wasi_addr));
+    if (__WASI_ERRNO_SUCCESS != error) {
+        return error;
+    }
+
+    if (IPv4 == wasi_addr.kind) {
+        struct sockaddr_in sock_addr_in = { 0 };
+
+        sock_addr_in.sin_family = AF_INET;
+        sock_addr_in.sin_addr.s_addr = (wasi_addr.addr.ip4.addr.n3 << 24)
+                                       | (wasi_addr.addr.ip4.addr.n2 << 16)
+                                       | (wasi_addr.addr.ip4.addr.n1 << 8)
+                                       | wasi_addr.addr.ip4.addr.n0;
+        sock_addr_in.sin_port = htons(wasi_addr.addr.ip4.port);
+        memcpy(sock_addr, &sock_addr_in, sizeof(sock_addr_in));
+
+        *addrlen = sizeof(sock_addr_in);
+    }
+    else if (IPv6 == wasi_addr.kind) {
+        // TODO: IPV6
+        return __WASI_ERRNO_AFNOSUPPORT;
+    }
+    else {
+        return __WASI_ERRNO_AFNOSUPPORT;
+    }
+
+    return __WASI_ERRNO_SUCCESS;
+}
+
+int
+accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
+{
+    __wasi_addr_t wasi_addr = { 0 };
+    __wasi_fd_t new_sockfd;
+    __wasi_errno_t error;
+
+    error = __wasi_sock_accept(sockfd, &new_sockfd);
+    HANDLE_ERROR(error)
+
+    // error = sock_addr_remote(new_sockfd, addr, addrlen);
+    // HANDLE_ERROR(error)
+    *addrlen = 0;
+
+    return new_sockfd;
+}
+
+int
+bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+    __wasi_addr_t wasi_addr = { 0 };
+    __wasi_errno_t error;
+
+    error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr);
+    HANDLE_ERROR(error)
+
+    error = __wasi_sock_bind(sockfd, &wasi_addr);
+    HANDLE_ERROR(error)
+
+    return __WASI_ERRNO_SUCCESS;
+}
+
+int
+connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+    __wasi_addr_t wasi_addr = { 0 };
+    __wasi_errno_t error;
+
+    error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr);
+    HANDLE_ERROR(error)
+
+    error = __wasi_sock_connect(sockfd, &wasi_addr);
+    HANDLE_ERROR(error)
+
+    return __WASI_ERRNO_SUCCESS;
+}
+
+int
+listen(int sockfd, int backlog)
+{
+    __wasi_errno_t error = __wasi_sock_listen(sockfd, backlog);
+    HANDLE_ERROR(error)
+    return __WASI_ERRNO_SUCCESS;
+}
+
+int
+socket(int domain, int type, int protocol)
+{
+    // the stub of address pool fd
+    __wasi_fd_t poolfd = -1;
+    __wasi_fd_t sockfd;
+    __wasi_errno_t error;
+    __wasi_address_family_t af;
+    __wasi_sock_type_t socktype;
+
+    if (AF_INET == domain) {
+        af = INET4;
+    }
+    else if (AF_INET6 == domain) {
+        af = INET6;
+    }
+    else {
+        return __WASI_ERRNO_NOPROTOOPT;
+    }
+
+    if (SOCK_DGRAM == type) {
+        socktype = SOCKET_DGRAM;
+    }
+    else if (SOCK_STREAM == type) {
+        socktype = SOCKET_STREAM;
+    }
+    else {
+        return __WASI_ERRNO_NOPROTOOPT;
+    }
+
+    error = __wasi_sock_open(poolfd, af, socktype, &sockfd);
+    HANDLE_ERROR(error)
+
+    return sockfd;
+}

+ 254 - 63
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c

@@ -50,6 +50,7 @@ typedef struct WASIContext {
     struct fd_table *curfds;
     struct fd_prestats *prestats;
     struct argv_environ_values *argv_environ;
+    struct addr_pool *addr_pool;
     char *argv_buf;
     char **argv_list;
     char *env_buf;
@@ -83,6 +84,14 @@ wasi_ctx_get_prestats(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx)
     return wasi_ctx->prestats;
 }
 
+static inline struct addr_pool *
+wasi_ctx_get_addr_pool(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx)
+{
+    if (!wasi_ctx)
+        return NULL;
+    return wasi_ctx->addr_pool;
+}
+
 static wasi_errno_t
 wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf)
 {
@@ -986,113 +995,278 @@ wasi_random_get(wasm_exec_env_t exec_env, void *buf, uint32 buf_len)
     return wasmtime_ssp_random_get(buf, buf_len);
 }
 
+static wasi_errno_t
+wasi_sock_accept(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_fd_t *fd_new)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasi_ssp_sock_accept(curfds, fd, fd_new);
+}
+
+static wasi_errno_t
+wasi_sock_addr_local(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *buf,
+                     wasi_size_t buf_len)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasi_ssp_sock_addr_local(curfds, fd, buf, buf_len);
+}
+
+static wasi_errno_t
+wasi_sock_addr_remote(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *buf,
+                      wasi_size_t buf_len)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasi_ssp_sock_addr_remote(curfds, fd, buf, buf_len);
+}
+
+static wasi_errno_t
+wasi_sock_addr_resolve(wasm_exec_env_t exec_env, wasi_fd_t fd, const char *host,
+                       wasi_ip_port_t port, uint8 *buf, wasi_size_t size)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_bind(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_addr_t *addr)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+    struct addr_pool *addr_pool = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+    addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx);
+
+    return wasi_ssp_sock_bind(curfds, addr_pool, fd, addr);
+}
+
+static wasi_errno_t
+wasi_sock_close(wasm_exec_env_t exec_env, wasi_fd_t fd)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_addr_t *addr)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+    struct addr_pool *addr_pool = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+    addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx);
+
+    return wasi_ssp_sock_connect(curfds, addr_pool, fd, addr);
+}
+
+static wasi_errno_t
+wasi_sock_get_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                            wasi_size_t *size)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_get_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_get_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_get_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                            wasi_size_t *size)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_listen(wasm_exec_env_t exec_env, wasi_fd_t fd, uint32 backlog)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasi_ssp_sock_listen(curfds, fd, backlog);
+}
+
+static wasi_errno_t
+wasi_sock_open(wasm_exec_env_t exec_env, wasi_fd_t poolfd,
+               wasi_address_family_t af, wasi_sock_type_t socktype,
+               wasi_fd_t *sockfd)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasi_ssp_sock_open(curfds, poolfd, af, socktype, sockfd);
+}
+
+static wasi_errno_t
+wasi_sock_set_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                            wasi_size_t size)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_set_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_set_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse)
+{
+    return __WASI_ENOSYS;
+}
+
+static wasi_errno_t
+wasi_sock_set_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                            wasi_size_t size)
+{
+    return __WASI_ENOSYS;
+}
+
 static wasi_errno_t
 wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data,
-               uint32 ri_data_len, wasi_riflags_t ri_flags,
-               uint32 *ro_datalen_app, wasi_roflags_t *ro_flags)
+               uint32 ri_data_len, wasi_riflags_t ri_flags, uint32 *ro_data_len,
+               wasi_roflags_t *ro_flags)
 {
+    /**
+     * ri_data_len is the length of a list of iovec_app_t, which head is
+     * ri_data. ro_data_len is the number of bytes received
+     **/
     wasm_module_inst_t module_inst = get_module_inst(exec_env);
     wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
     struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
-    wasi_iovec_t *iovec, *iovec_begin;
     uint64 total_size;
-    size_t ro_datalen;
     uint32 i;
     wasi_errno_t err;
 
     if (!wasi_ctx)
-        return (wasi_errno_t)-1;
+        return __WASI_EINVAL;
 
     total_size = sizeof(iovec_app_t) * (uint64)ri_data_len;
-    if (!validate_native_addr(ro_datalen_app, (uint32)sizeof(uint32))
+    if (!validate_native_addr(ro_data_len, (uint32)sizeof(uint32))
         || !validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t))
         || total_size >= UINT32_MAX
         || !validate_native_addr(ri_data, (uint32)total_size))
-        return (wasi_errno_t)-1;
-
-    total_size = sizeof(wasi_iovec_t) * (uint64)ri_data_len;
-    if (total_size >= UINT32_MAX
-        || !(iovec_begin = wasm_runtime_malloc((uint32)total_size)))
-        return (wasi_errno_t)-1;
+        return __WASI_EINVAL;
 
-    iovec = iovec_begin;
+    /* recv ri_data one by one */
+    *ro_data_len = 0;
+    for (i = 0; i < ri_data_len; ri_data++, i++) {
+        void *buf;
+        size_t bytes_recv;
 
-    for (i = 0; i < ri_data_len; i++, ri_data++, iovec++) {
         if (!validate_app_addr(ri_data->buf_offset, ri_data->buf_len)) {
-            err = (wasi_errno_t)-1;
-            goto fail;
+            return __WASI_EINVAL;
         }
-        iovec->buf = (void *)addr_app_to_native(ri_data->buf_offset);
-        iovec->buf_len = ri_data->buf_len;
-    }
-
-    err = wasmtime_ssp_sock_recv(curfds, sock, iovec_begin, ri_data_len,
-                                 ri_flags, &ro_datalen, ro_flags);
-    if (err)
-        goto fail;
-
-    *(uint32 *)ro_datalen_app = (uint32)ro_datalen;
 
-    /* success */
-    err = 0;
+        buf = (void *)addr_app_to_native(ri_data->buf_offset);
+        err = wasmtime_ssp_sock_recv(curfds, sock, buf, ri_data->buf_len,
+                                     &bytes_recv);
+        if (err != __WASI_ESUCCESS) {
+            return err;
+        }
+        *ro_data_len += bytes_recv;
+    }
 
-fail:
-    wasm_runtime_free(iovec_begin);
-    return err;
+    *ro_flags = ri_flags;
+    return __WASI_ESUCCESS;
 }
 
 static wasi_errno_t
 wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock,
                const iovec_app_t *si_data, uint32 si_data_len,
-               wasi_siflags_t si_flags, uint32 *so_datalen_app)
+               wasi_siflags_t si_flags, uint32 *so_data_len)
 {
+    /**
+     * si_data_len is the length of a list of iovec_app_t, which head is
+     * si_data. so_data_len is the number of bytes sent
+     **/
     wasm_module_inst_t module_inst = get_module_inst(exec_env);
     wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
     struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
-    wasi_ciovec_t *ciovec, *ciovec_begin;
     uint64 total_size;
-    size_t so_datalen;
     uint32 i;
     wasi_errno_t err;
 
     if (!wasi_ctx)
-        return (wasi_errno_t)-1;
+        return __WASI_EINVAL;
 
     total_size = sizeof(iovec_app_t) * (uint64)si_data_len;
-    if (!validate_native_addr(so_datalen_app, sizeof(uint32))
+    if (!validate_native_addr(so_data_len, sizeof(uint32))
         || total_size >= UINT32_MAX
         || !validate_native_addr((void *)si_data, (uint32)total_size))
-        return (wasi_errno_t)-1;
+        return __WASI_EINVAL;
 
-    total_size = sizeof(wasi_ciovec_t) * (uint64)si_data_len;
-    if (total_size >= UINT32_MAX
-        || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size)))
-        return (wasi_errno_t)-1;
-
-    ciovec = ciovec_begin;
+    /* send si_data one by one */
+    *so_data_len = 0;
+    for (i = 0; i < si_data_len; i++, si_data++) {
+        void *buf;
+        size_t bytes_sent;
 
-    for (i = 0; i < si_data_len; i++, si_data++, ciovec++) {
         if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) {
-            err = (wasi_errno_t)-1;
-            goto fail;
+            return __WASI_EINVAL;
         }
-        ciovec->buf = (char *)addr_app_to_native(si_data->buf_offset);
-        ciovec->buf_len = si_data->buf_len;
-    }
-
-    err = wasmtime_ssp_sock_send(curfds, sock, ciovec_begin, si_data_len,
-                                 si_flags, &so_datalen);
-    if (err)
-        goto fail;
-
-    *so_datalen_app = (uint32)so_datalen;
 
-    /* success */
-    err = 0;
+        buf = (void *)addr_app_to_native(si_data->buf_offset);
+        err = wasmtime_ssp_sock_send(curfds, sock, buf, si_data->buf_len,
+                                     &bytes_sent);
+        if (err != __WASI_ESUCCESS) {
+            return err;
+        }
+        *so_data_len += bytes_sent;
+    }
 
-fail:
-    wasm_runtime_free(ciovec_begin);
-    return err;
+    return __WASI_ESUCCESS;
 }
 
 static wasi_errno_t
@@ -1103,9 +1277,9 @@ wasi_sock_shutdown(wasm_exec_env_t exec_env, wasi_fd_t sock, wasi_sdflags_t how)
     struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
 
     if (!wasi_ctx)
-        return (wasi_errno_t)-1;
+        return __WASI_EINVAL;
 
-    return wasmtime_ssp_sock_shutdown(curfds, sock, how);
+    return wasmtime_ssp_sock_shutdown(curfds, sock);
 }
 
 static wasi_errno_t
@@ -1161,8 +1335,25 @@ static NativeSymbol native_symbols_libc_wasi[] = {
     REG_NATIVE_FUNC(proc_exit, "(i)"),
     REG_NATIVE_FUNC(proc_raise, "(i)i"),
     REG_NATIVE_FUNC(random_get, "(*~)i"),
+    REG_NATIVE_FUNC(sock_accept, "(i*)i"),
+    REG_NATIVE_FUNC(sock_addr_local, "(i*i)i"),
+    REG_NATIVE_FUNC(sock_addr_remote, "(i*i)i"),
+    REG_NATIVE_FUNC(sock_addr_resolve, "(i*i*i)i"),
+    REG_NATIVE_FUNC(sock_bind, "(i*)i"),
+    REG_NATIVE_FUNC(sock_close, "(i)i"),
+    REG_NATIVE_FUNC(sock_connect, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_recv_buf_size, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_reuse_addr, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_reuse_port, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_send_buf_size, "(i*)i"),
+    REG_NATIVE_FUNC(sock_listen, "(ii)i"),
+    REG_NATIVE_FUNC(sock_open, "(iii*)i"),
     REG_NATIVE_FUNC(sock_recv, "(i*ii**)i"),
     REG_NATIVE_FUNC(sock_send, "(i*ii*)i"),
+    REG_NATIVE_FUNC(sock_set_recv_buf_size, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_reuse_addr, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_reuse_port, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_send_buf_size, "(ii)i"),
     REG_NATIVE_FUNC(sock_shutdown, "(ii)i"),
     REG_NATIVE_FUNC(sched_yield, "()i"),
 };

+ 27 - 22
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h

@@ -13,38 +13,43 @@
 extern "C" {
 #endif
 
+typedef __wasi_address_family_t wasi_address_family_t;
+typedef __wasi_addr_t wasi_addr_t;
+typedef __wasi_advice_t wasi_advice_t;
+typedef __wasi_ciovec_t wasi_ciovec_t;
+typedef __wasi_clockid_t wasi_clockid_t;
+typedef __wasi_dircookie_t wasi_dircookie_t;
 typedef __wasi_errno_t wasi_errno_t;
+typedef __wasi_event_t wasi_event_t;
+typedef __wasi_exitcode_t wasi_exitcode_t;
+typedef __wasi_fdflags_t wasi_fdflags_t;
+typedef __wasi_fdstat_t wasi_fdstat_t;
 typedef __wasi_fd_t wasi_fd_t;
-typedef __wasi_clockid_t wasi_clockid_t;
-typedef __wasi_timestamp_t wasi_timestamp_t;
-typedef __wasi_prestat_t wasi_prestat_t;
-typedef __wasi_iovec_t wasi_iovec_t;
-typedef __wasi_ciovec_t wasi_ciovec_t;
-typedef __wasi_filetype_t wasi_filetype_t;
-typedef __wasi_filesize_t wasi_filesize_t;
 typedef __wasi_filedelta_t wasi_filedelta_t;
-typedef __wasi_whence_t wasi_whence_t;
-typedef __wasi_fdstat_t wasi_fdstat_t;
-typedef __wasi_fdflags_t wasi_fdflags_t;
-typedef __wasi_rights_t wasi_rights_t;
-typedef __wasi_advice_t wasi_advice_t;
-typedef __wasi_lookupflags_t wasi_lookupflags_t;
-typedef __wasi_oflags_t wasi_oflags_t;
-typedef __wasi_dircookie_t wasi_dircookie_t;
+typedef __wasi_filesize_t wasi_filesize_t;
 typedef __wasi_filestat_t wasi_filestat_t;
+typedef __wasi_filetype_t wasi_filetype_t;
 typedef __wasi_fstflags_t wasi_fstflags_t;
-typedef __wasi_subscription_t wasi_subscription_t;
-typedef __wasi_event_t wasi_event_t;
-typedef __wasi_exitcode_t wasi_exitcode_t;
-typedef __wasi_signal_t wasi_signal_t;
+typedef __wasi_iovec_t wasi_iovec_t;
+typedef __wasi_ip_port_t wasi_ip_port_t;
+typedef __wasi_lookupflags_t wasi_lookupflags_t;
+typedef __wasi_oflags_t wasi_oflags_t;
+typedef __wasi_preopentype_t wasi_preopentype_t;
+typedef __wasi_prestat_t wasi_prestat_t;
 typedef __wasi_riflags_t wasi_riflags_t;
+typedef __wasi_rights_t wasi_rights_t;
 typedef __wasi_roflags_t wasi_roflags_t;
-typedef __wasi_siflags_t wasi_siflags_t;
 typedef __wasi_sdflags_t wasi_sdflags_t;
-typedef __wasi_preopentype_t wasi_preopentype_t;
+typedef __wasi_siflags_t wasi_siflags_t;
+typedef __wasi_signal_t wasi_signal_t;
+typedef __wasi_size_t wasi_size_t;
+typedef __wasi_sock_type_t wasi_sock_type_t;
+typedef __wasi_subscription_t wasi_subscription_t;
+typedef __wasi_timestamp_t wasi_timestamp_t;
+typedef __wasi_whence_t wasi_whence_t;
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* end of _LIBC_WASI_WRAPPER_H */
+#endif /* end of _LIBC_WASI_WRAPPER_H */

+ 155 - 40
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h

@@ -49,6 +49,9 @@ _Static_assert(_Alignof(int64_t) == 8, "non-wasi data layout");
 _Static_assert(_Alignof(uint64_t) == 8, "non-wasi data layout");
 #endif
 
+typedef uint32_t __wasi_size_t;
+_Static_assert(_Alignof(__wasi_size_t) == 4, "non-wasi data layout");
+
 typedef uint8_t __wasi_advice_t;
 #define __WASI_ADVICE_NORMAL     (0)
 #define __WASI_ADVICE_SEQUENTIAL (1)
@@ -211,35 +214,44 @@ typedef uint64_t __wasi_rights_t;
  * Observe that WASI defines rights in the plural form
  * TODO: refactor to use RIGHTS instead of RIGHT
  */
-#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(1 << 0))
-#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(1 << 1))
-#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(1 << 2))
-#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(1 << 3))
-#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(1 << 4))
-#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(1 << 5))
-#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(1 << 6))
-#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(1 << 7))
-#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(1 << 8))
-#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(1 << 9))
-#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(1 << 10))
-#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(1 << 11))
-#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(1 << 12))
-#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(1 << 13))
-#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(1 << 14))
-#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(1 << 15))
-#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(1 << 16))
-#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(1 << 17))
-#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(1 << 18))
-#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(1 << 19))
-#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(1 << 20))
-#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(1 << 21))
-#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(1 << 22))
-#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(1 << 23))
-#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(1 << 24))
-#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(1 << 25))
-#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(1 << 26))
-#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(1 << 27))
-#define __WASI_RIGHT_SOCK_SHUTDOWN ((__wasi_rights_t)(1 << 28))
+#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(UINT64_C(1) << 0))
+#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(UINT64_C(1) << 1))
+#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(UINT64_C(1) << 2))
+#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(UINT64_C(1) << 3))
+#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(UINT64_C(1) << 4))
+#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(UINT64_C(1) << 5))
+#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(UINT64_C(1) << 6))
+#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(UINT64_C(1) << 7))
+#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(UINT64_C(1) << 8))
+#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 9))
+#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(UINT64_C(1) << 10))
+#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 11))
+#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(UINT64_C(1) << 12))
+#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(UINT64_C(1) << 13))
+#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(UINT64_C(1) << 14))
+#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(UINT64_C(1) << 15))
+#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 16))
+#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(UINT64_C(1) << 17))
+#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 18))
+#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 19))
+#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 20))
+#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 21))
+#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 22))
+#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 23))
+#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(UINT64_C(1) << 24))
+#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 25))
+#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(UINT64_C(1) << 26))
+#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(UINT64_C(1) << 27))
+#define __WASI_RIGHT_SOCK_CONNECT ((__wasi_rights_t)(UINT64_C(1) << 28))
+#define __WASI_RIGHT_SOCK_LISTEN ((__wasi_rights_t)(UINT64_C(1) << 29))
+#define __WASI_RIGHT_SOCK_BIND ((__wasi_rights_t)(UINT64_C(1) << 30))
+#define __WASI_RIGHT_SOCK_ACCEPT ((__wasi_rights_t)(UINT64_C(1) << 31))
+#define __WASI_RIGHT_SOCK_RECV ((__wasi_rights_t)(UINT64_C(1) << 32))
+#define __WASI_RIGHT_SOCK_SEND ((__wasi_rights_t)(UINT64_C(1) << 33))
+#define __WASI_RIGHT_SOCK_ADDR_LOCAL ((__wasi_rights_t)(UINT64_C(1) << 34))
+#define __WASI_RIGHT_SOCK_ADDR_REMOTE ((__wasi_rights_t)(UINT64_C(1) << 35))
+#define __WASI_RIGHT_SOCK_RECV_FROM ((__wasi_rights_t)(UINT64_C(1) << 36))
+#define __WASI_RIGHT_SOCK_SEND_TO ((__wasi_rights_t)(UINT64_C(1) << 37))
 
 typedef uint16_t __wasi_roflags_t;
 #define __WASI_SOCK_RECV_DATA_TRUNCATED (0x0001)
@@ -301,6 +313,7 @@ typedef uint8_t __wasi_preopentype_t;
 struct fd_table;
 struct fd_prestats;
 struct argv_environ_values;
+struct addr_pool;
 
 typedef struct __wasi_dirent_t {
     __wasi_dircookie_t d_next;
@@ -536,6 +549,55 @@ _Static_assert(_Alignof(__wasi_subscription_t) == 8, "witx calculated align");
 _Static_assert(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset");
 _Static_assert(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset");
 
+/* keep syncing with wasi_socket_ext.h */
+typedef enum {
+    SOCKET_DGRAM = 0,
+    SOCKET_STREAM,
+} __wasi_sock_type_t;
+
+typedef uint16_t __wasi_ip_port_t;
+
+typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t;
+
+/* n0.n1.n2.n3 */
+typedef struct __wasi_addr_ip4_t {
+    uint8_t n0;
+    uint8_t n1;
+    uint8_t n2;
+    uint8_t n3;
+} __wasi_addr_ip4_t;
+
+typedef struct __wasi_addr_ip4_port_t {
+    __wasi_addr_ip4_t addr;
+    __wasi_ip_port_t port;
+} __wasi_addr_ip4_port_t;
+
+typedef struct __wasi_addr_ip6_t {
+    uint16_t n0;
+    uint16_t n1;
+    uint16_t n2;
+    uint16_t n3;
+    uint16_t h0;
+    uint16_t h1;
+    uint16_t h2;
+    uint16_t h3;
+} __wasi_addr_ip6_t;
+
+typedef struct __wasi_addr_ip6_port_t {
+    __wasi_addr_ip6_t addr;
+    __wasi_ip_port_t port;
+} __wasi_addr_ip6_port_t;
+
+typedef struct __wasi_addr_t {
+    __wasi_addr_type_t kind;
+    union {
+        __wasi_addr_ip4_port_t ip4;
+        __wasi_addr_ip6_port_t ip6;
+    } addr;
+} __wasi_addr_t;
+
+typedef enum { INET4 = 0, INET6 } __wasi_address_family_t;
+
 #if defined(WASMTIME_SSP_WASI_API)
 #define WASMTIME_SSP_SYSCALL_NAME(name) \
     asm("__wasi_" #name)
@@ -920,16 +982,71 @@ __wasi_errno_t wasmtime_ssp_random_get(
     size_t buf_len
 ) WASMTIME_SSP_SYSCALL_NAME(random_get) __attribute__((__warn_unused_result__));
 
+__wasi_errno_t
+wasi_ssp_sock_accept(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t fd, __wasi_fd_t *fd_new
+) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t
+wasi_ssp_sock_addr_local(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len
+) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t
+wasi_ssp_sock_addr_remote(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len
+) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t
+wasi_ssp_sock_open(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t poolfd, __wasi_address_family_t af, __wasi_sock_type_t socktype,
+    __wasi_fd_t *sockfd
+) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t
+wasi_ssp_sock_bind(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds, struct addr_pool *addr_pool,
+#endif
+    __wasi_fd_t fd, __wasi_addr_t *addr
+) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t
+wasi_ssp_sock_connect(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds, struct addr_pool *addr_pool,
+#endif
+    __wasi_fd_t fd, __wasi_addr_t *addr
+) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t
+wasi_ssp_sock_listen(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t fd, __wasi_size_t backlog
+) __attribute__((__warn_unused_result__));
+
 __wasi_errno_t wasmtime_ssp_sock_recv(
 #if !defined(WASMTIME_SSP_STATIC_CURFDS)
     struct fd_table *curfds,
 #endif
     __wasi_fd_t sock,
-    const __wasi_iovec_t *ri_data,
-    size_t ri_data_len,
-    __wasi_riflags_t ri_flags,
-    size_t *ro_datalen,
-    __wasi_roflags_t *ro_flags
+    void *buf,
+    size_t buf_len,
+    size_t *recv_len
 ) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__));
 
 __wasi_errno_t wasmtime_ssp_sock_send(
@@ -937,18 +1054,16 @@ __wasi_errno_t wasmtime_ssp_sock_send(
     struct fd_table *curfds,
 #endif
     __wasi_fd_t sock,
-    const __wasi_ciovec_t *si_data,
-    size_t si_data_len,
-    __wasi_siflags_t si_flags,
-    size_t *so_datalen
+    const void *buf,
+    size_t buf_len,
+    size_t *sent_len
 ) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__));
 
 __wasi_errno_t wasmtime_ssp_sock_shutdown(
 #if !defined(WASMTIME_SSP_STATIC_CURFDS)
     struct fd_table *curfds,
 #endif
-    __wasi_fd_t sock,
-    __wasi_sdflags_t how
+    __wasi_fd_t sock
 ) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__));
 
 __wasi_errno_t wasmtime_ssp_sched_yield(void)

+ 331 - 64
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c

@@ -60,6 +60,7 @@ static_assert(sizeof(struct iovec) == sizeof(__wasi_ciovec_t),
 static __thread struct fd_table *curfds;
 static __thread struct fd_prestats *prestats;
 static __thread struct argv_environ_values *argv_environ;
+static __thread struct addr_pool *addr_pool;
 #endif
 
 // Converts a POSIX error code to a CloudABI error code.
@@ -2716,113 +2717,294 @@ wasmtime_ssp_random_get(void *buf, size_t nbyte)
 }
 
 __wasi_errno_t
-wasmtime_ssp_sock_recv(
+wasi_ssp_sock_accept(
 #if !defined(WASMTIME_SSP_STATIC_CURFDS)
     struct fd_table *curfds,
 #endif
-    __wasi_fd_t sock, const __wasi_iovec_t *ri_data, size_t ri_data_len,
-    __wasi_riflags_t ri_flags, size_t *ro_datalen, __wasi_roflags_t *ro_flags)
+    __wasi_fd_t fd, __wasi_fd_t *fd_new)
 {
-    // Convert input to msghdr.
-    struct msghdr hdr = {
-        .msg_iov = (struct iovec *)ri_data,
-        .msg_iovlen = ri_data_len,
-    };
-    int nflags = 0;
-    if ((ri_flags & __WASI_SOCK_RECV_PEEK) != 0)
-        nflags |= MSG_PEEK;
-    if ((ri_flags & __WASI_SOCK_RECV_WAITALL) != 0)
-        nflags |= MSG_WAITALL;
-
+    __wasi_filetype_t wasi_type;
+    __wasi_rights_t max_base, max_inheriting;
     struct fd_object *fo;
+    bh_socket_t new_sock;
+    int ret;
     __wasi_errno_t error =
-        fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0);
-    if (error != 0) {
+        fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ACCEPT, 0);
+    if (error != __WASI_ESUCCESS)
         return error;
-    }
 
-    ssize_t datalen = recvmsg(fd_number(fo), &hdr, nflags);
+    ret = os_socket_accept(fd_number(fo), &new_sock, NULL, NULL);
     fd_object_release(fo);
-    if (datalen < 0) {
+    if (ret == BHT_ERROR)
         return convert_errno(errno);
+
+    error = fd_determine_type_rights(new_sock, &wasi_type, &max_base,
+                                     &max_inheriting);
+    if (error != __WASI_ESUCCESS) {
+        os_socket_close(ret);
+        return error;
     }
 
-    // Convert msghdr to output.
-    *ro_datalen = (size_t)datalen;
-    *ro_flags = 0;
-    if ((hdr.msg_flags & MSG_TRUNC) != 0)
-        *ro_flags |= __WASI_SOCK_RECV_DATA_TRUNCATED;
-    return 0;
+    error = fd_table_insert_fd(curfds, new_sock, wasi_type, max_base,
+                               max_inheriting, fd_new);
+    if (error != __WASI_ESUCCESS) {
+        os_socket_close(ret);
+        return error;
+    }
+
+    return __WASI_ESUCCESS;
 }
 
 __wasi_errno_t
-wasmtime_ssp_sock_send(
+wasi_ssp_sock_addr_local(
 #if !defined(WASMTIME_SSP_STATIC_CURFDS)
     struct fd_table *curfds,
 #endif
-    __wasi_fd_t sock, const __wasi_ciovec_t *si_data, size_t si_data_len,
-    __wasi_siflags_t si_flags, size_t *so_datalen) NO_LOCK_ANALYSIS
+    __wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len)
 {
-    // Convert input to msghdr.
-    struct msghdr hdr = {
-        .msg_iov = (struct iovec *)si_data,
-        .msg_iovlen = si_data_len,
-    };
+    struct fd_object *fo;
+    __wasi_errno_t error =
+        fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0);
+    if (error != __WASI_ESUCCESS)
+        return error;
+
+    fd_object_release(fo);
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+wasi_ssp_sock_addr_remote(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len)
+{
+    struct fd_object *fo;
+    __wasi_errno_t error =
+        fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_REMOTE, 0);
+    if (error != __WASI_ESUCCESS)
+        return error;
+
+    fd_object_release(fo);
+    return __WASI_ENOSYS;
+}
+
+__wasi_errno_t
+wasi_ssp_sock_bind(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds, struct addr_pool *addr_pool,
+#endif
+    __wasi_fd_t fd, __wasi_addr_t *addr)
+{
+    char buf[24] = { 0 };
+    const char *format = "%u.%u.%u.%u";
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int port = addr->addr.ip4.port;
+    int ret;
+
+    snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1,
+             addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3);
+
+    if (!addr_pool_search(addr_pool, buf)) {
+        return __WASI_EACCES;
+    }
+
+    error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_BIND, 0);
+    if (error != __WASI_ESUCCESS)
+        return error;
+
+    ret = os_socket_bind(fd_number(fo), buf, &port);
+    fd_object_release(fo);
+    if (ret == BHT_ERROR) {
+        return convert_errno(errno);
+    }
+
+    return __WASI_ESUCCESS;
+}
 
-    // Attach file descriptors if present.
+__wasi_errno_t
+wasi_ssp_sock_connect(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds, struct addr_pool *addr_pool,
+#endif
+    __wasi_fd_t fd, __wasi_addr_t *addr)
+{
+    char buf[24] = { 0 };
+    const char *format = "%u.%u.%u.%u";
+    struct fd_object *fo;
     __wasi_errno_t error;
+    int ret;
+
+    snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1,
+             addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3);
 
-    // Send message.
+    if (!addr_pool_search(addr_pool, buf)) {
+        return __WASI_EACCES;
+    }
+
+    error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_BIND, 0);
+    if (error != __WASI_ESUCCESS)
+        return error;
+
+    ret = os_socket_connect(fd_number(fo), buf, addr->addr.ip4.port);
+    fd_object_release(fo);
+    if (ret == BHT_ERROR) {
+        return convert_errno(errno);
+    }
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasi_ssp_sock_listen(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t fd, __wasi_size_t backlog)
+{
     struct fd_object *fo;
-    error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0);
-    if (error != 0)
-        goto out;
-    ssize_t len = sendmsg(fd_number(fo), &hdr, 0);
+    int ret;
+    __wasi_errno_t error =
+        fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_LISTEN, 0);
+    if (error != __WASI_ESUCCESS)
+        return error;
+
+    ret = os_socket_listen(fd_number(fo), backlog);
     fd_object_release(fo);
-    if (len < 0) {
-        error = convert_errno(errno);
+    if (ret == BHT_ERROR) {
+        return convert_errno(errno);
+    }
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasi_ssp_sock_open(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t poolfd, __wasi_address_family_t af, __wasi_sock_type_t socktype,
+    __wasi_fd_t *sockfd)
+{
+    bh_socket_t sock;
+    int tcp_or_udp = 0;
+    int ret;
+    __wasi_filetype_t wasi_type;
+    __wasi_rights_t max_base, max_inheriting;
+    __wasi_errno_t error;
+
+    (void)poolfd;
+
+    if (INET4 != af) {
+        return __WASI_EAFNOSUPPORT;
+    }
+
+    tcp_or_udp = SOCKET_DGRAM == socktype ? 0 : 1;
+
+    ret = os_socket_create(&sock, tcp_or_udp);
+    if (ret == BHT_ERROR) {
+        return convert_errno(errno);
+    }
+
+    error =
+        fd_determine_type_rights(sock, &wasi_type, &max_base, &max_inheriting);
+    if (error != __WASI_ESUCCESS) {
+        os_socket_close(ret);
+        return error;
+    }
+
+    if (SOCKET_DGRAM == socktype) {
+        assert(wasi_type == __WASI_FILETYPE_SOCKET_DGRAM);
     }
     else {
-        *so_datalen = (size_t)len;
+        assert(wasi_type == __WASI_FILETYPE_SOCKET_STREAM);
     }
 
-out:
-    return error;
+    // TODO: base rights and inheriting rights ?
+    error = fd_table_insert_fd(curfds, sock, wasi_type, max_base,
+                               max_inheriting, sockfd);
+    if (error != __WASI_ESUCCESS) {
+        os_socket_close(ret);
+        return error;
+    }
+
+    return __WASI_ESUCCESS;
 }
 
 __wasi_errno_t
-wasmtime_ssp_sock_shutdown(
+wasmtime_ssp_sock_recv(
 #if !defined(WASMTIME_SSP_STATIC_CURFDS)
     struct fd_table *curfds,
 #endif
-    __wasi_fd_t sock, __wasi_sdflags_t how)
+    __wasi_fd_t sock, void *buf, size_t buf_len, size_t *recv_len)
 {
-    int nhow;
-    switch (how) {
-        case __WASI_SHUT_RD:
-            nhow = SHUT_RD;
-            break;
-        case __WASI_SHUT_WR:
-            nhow = SHUT_WR;
-            break;
-        case __WASI_SHUT_RD | __WASI_SHUT_WR:
-            nhow = SHUT_RDWR;
-            break;
-        default:
-            return __WASI_EINVAL;
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int ret;
+
+    error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0);
+    if (error != 0) {
+        return error;
     }
 
+    ret = os_socket_recv(fd_number(fo), buf, buf_len);
+    fd_object_release(fo);
+    if (ret == BHT_ERROR) {
+        return convert_errno(errno);
+    }
+
+    *recv_len = (size_t)ret;
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasmtime_ssp_sock_send(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, const void *buf, size_t buf_len, size_t *sent_len)
+{
     struct fd_object *fo;
-    __wasi_errno_t error =
-        fd_object_get(curfds, &fo, sock, __WASI_RIGHT_SOCK_SHUTDOWN, 0);
+    __wasi_errno_t error;
+    int ret;
+
+    error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0);
+    if (error != 0) {
+        return error;
+    }
+
+    ret = os_socket_send(fd_number(fo), buf, buf_len);
+    fd_object_release(fo);
+    if (ret == BHT_ERROR) {
+        return convert_errno(errno);
+    }
+
+    *sent_len = (size_t)ret;
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasmtime_ssp_sock_shutdown(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock)
+{
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int ret;
+
+    error = fd_object_get(curfds, &fo, sock, 0, 0);
     if (error != 0)
         return error;
 
-    int ret = shutdown(fd_number(fo), nhow);
+    ret = os_socket_shutdown(fd_number(fo));
     fd_object_release(fo);
-    if (ret < 0)
+    if (ret == BHT_ERROR)
         return convert_errno(errno);
-    return 0;
+
+    return __WASI_ESUCCESS;
 }
 
 __wasi_errno_t
@@ -2943,3 +3125,88 @@ fd_prestats_destroy(struct fd_prestats *pt)
         wasm_runtime_free(pt->prestats);
     }
 }
+
+bool
+addr_pool_init(struct addr_pool *addr_pool)
+{
+    addr_pool->next = NULL;
+    addr_pool->addr = 0;
+    addr_pool->mask = 0;
+    return true;
+}
+
+bool
+addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
+{
+    struct addr_pool *cur = addr_pool;
+    struct addr_pool *next;
+
+    if (!addr_pool) {
+        return false;
+    }
+
+    if (!(next = wasm_runtime_malloc(sizeof(struct addr_pool)))) {
+        return false;
+    }
+
+    next->next = NULL;
+    next->mask = mask;
+    if (os_socket_inet_network(addr, &next->addr) != BHT_OK) {
+        wasm_runtime_free(next);
+        return false;
+    }
+
+    /* attach with */
+    while (cur->next) {
+        cur = cur->next;
+    }
+    cur->next = next;
+    return true;
+}
+
+static bool
+compare_address(const struct addr_pool *addr_pool_entry, const char *addr)
+{
+    /* host order */
+    uint32 target;
+    uint32 address = addr_pool_entry->addr;
+    /* 0.0.0.0 means any address */
+    if (0 == address) {
+        return true;
+    }
+
+    if (os_socket_inet_network(addr, &target) != BHT_OK) {
+        return false;
+    }
+
+    uint32 mask = addr_pool_entry->mask;
+    uint32 first_address = address & mask;
+    uint32 last_address = address | (~mask);
+    return first_address <= target && target <= last_address;
+}
+
+bool
+addr_pool_search(struct addr_pool *addr_pool, const char *addr)
+{
+    struct addr_pool *cur = addr_pool->next;
+
+    while (cur) {
+        if (compare_address(cur, addr))
+            return true;
+        cur = cur->next;
+    }
+
+    return false;
+}
+
+void
+addr_pool_destroy(struct addr_pool *addr_pool)
+{
+    struct addr_pool *cur = addr_pool->next;
+
+    while (cur) {
+        struct addr_pool *next = cur->next;
+        wasm_runtime_free(cur);
+        cur = next;
+    }
+}

+ 16 - 0
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h

@@ -46,6 +46,13 @@ struct argv_environ_values {
     size_t environ_count;
 };
 
+struct addr_pool {
+    struct addr_pool *next;
+    /* addr and mask in host order */
+    uint32 addr;
+    uint8 mask;
+};
+
 bool
 fd_table_init(struct fd_table *);
 bool
@@ -66,4 +73,13 @@ fd_table_destroy(struct fd_table *ft);
 void
 fd_prestats_destroy(struct fd_prestats *pt);
 
+bool
+addr_pool_init(struct addr_pool *);
+bool
+addr_pool_insert(struct addr_pool *, const char *, uint8 mask);
+bool
+addr_pool_search(struct addr_pool *, const char *);
+void
+addr_pool_destroy(struct addr_pool *);
+
 #endif

+ 16 - 5
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h

@@ -32,7 +32,13 @@
    __WASI_RIGHT_FD_FILESTAT_SET_SIZE |                                     \
    __WASI_RIGHT_PATH_SYMLINK | __WASI_RIGHT_PATH_UNLINK_FILE |             \
    __WASI_RIGHT_PATH_REMOVE_DIRECTORY |                                    \
-   __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_SHUTDOWN)
+   __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_CONNECT |            \
+   __WASI_RIGHT_SOCK_LISTEN | __WASI_RIGHT_SOCK_BIND |                     \
+   __WASI_RIGHT_SOCK_ACCEPT | __WASI_RIGHT_SOCK_RECV |                     \
+   __WASI_RIGHT_SOCK_SEND | __WASI_RIGHT_SOCK_ADDR_LOCAL |                 \
+   __WASI_RIGHT_SOCK_ADDR_REMOTE | __WASI_RIGHT_SOCK_RECV_FROM |           \
+   __WASI_RIGHT_SOCK_SEND_TO)
+
 
 // Block and character device interaction is outside the scope of
 // CloudABI. Simply allow everything.
@@ -71,10 +77,15 @@
 #define RIGHTS_REGULAR_FILE_INHERITING 0
 
 // Operations that apply to sockets and socket pairs.
-#define RIGHTS_SOCKET_BASE                                     \
-  (__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS |   \
-   __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_FILESTAT_GET |      \
-   __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_SHUTDOWN)
+#define RIGHTS_SOCKET_BASE                                              \
+  (__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS |            \
+   __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_FILESTAT_GET |               \
+   __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_CONNECT |         \
+   __WASI_RIGHT_SOCK_LISTEN | __WASI_RIGHT_SOCK_BIND |                  \
+   __WASI_RIGHT_SOCK_ACCEPT | __WASI_RIGHT_SOCK_RECV |                  \
+   __WASI_RIGHT_SOCK_SEND | __WASI_RIGHT_SOCK_ADDR_LOCAL |              \
+   __WASI_RIGHT_SOCK_ADDR_REMOTE | __WASI_RIGHT_SOCK_RECV_FROM |        \
+   __WASI_RIGHT_SOCK_SEND_TO)
 #define RIGHTS_SOCKET_INHERITING RIGHTS_ALL
 
 // Operations that apply to TTYs.

+ 37 - 0
core/shared/platform/common/posix/posix_socket.c

@@ -8,6 +8,16 @@
 
 #include <arpa/inet.h>
 
+static void
+textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out)
+{
+    assert(textual);
+
+    out->sin_family = AF_INET;
+    out->sin_port = htons(port);
+    out->sin_addr.s_addr = inet_addr(textual);
+}
+
 int
 os_socket_create(bh_socket_t *sock, int tcp_or_udp)
 {
@@ -113,6 +123,23 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
     return BHT_OK;
 }
 
+int
+os_socket_connect(bh_socket_t socket, const char *addr, int port)
+{
+    struct sockaddr_in addr_in = { 0 };
+    socklen_t addr_len = sizeof(struct sockaddr_in);
+    int ret = 0;
+
+    textual_addr_to_sockaddr(addr, port, &addr_in);
+
+    ret = connect(socket, (struct sockaddr *)&addr_in, addr_len);
+    if (ret == -1) {
+        return BHT_ERROR;
+    }
+
+    return BHT_OK;
+}
+
 int
 os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
 {
@@ -138,3 +165,13 @@ os_socket_shutdown(bh_socket_t socket)
     shutdown(socket, O_RDWR);
     return BHT_OK;
 }
+
+int
+os_socket_inet_network(const char *cp, uint32 *out)
+{
+    if (!cp)
+        return BHT_ERROR;
+
+    *out = inet_network(cp);
+    return BHT_OK;
+}

+ 23 - 0
core/shared/platform/include/platform_api_extension.h

@@ -265,6 +265,17 @@ int
 os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
                  unsigned int *addrlen);
 
+/**
+ * initiate a connection on a socket
+ *
+ * @param socket the socket to connect with
+ * @param addr the ip address, only IPv4 supported currently
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_connect(bh_socket_t socket, const char *addr, int port);
+
 /**
  * Blocking receive message from a socket.
  *
@@ -310,6 +321,18 @@ os_socket_close(bh_socket_t socket);
 int
 os_socket_shutdown(bh_socket_t socket);
 
+/**
+ * converts cp into a number in host byte order suitable for use as
+ * an Internet network address
+ *
+ * @param cp a string in IPv4 numbers-and-dots notation
+ *
+ * @return On success, the converted address is  returned.
+ * If the input is invalid, -1 is returned
+ */
+int
+os_socket_inet_network(const char *cp, uint32 *out);
+
 #ifdef __cplusplus
 }
 #endif

+ 68 - 0
core/shared/platform/linux-sgx/sgx_socket.c

@@ -227,4 +227,72 @@ shutdown(int sockfd, int how)
     return ret;
 }
 
+int
+os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
+                 unsigned int *addrlen)
+
+{
+    errno = ENOSYS;
+    return -1;
+}
+int
+os_socket_bind(bh_socket_t socket, const char *host, int *port)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+int
+os_socket_close(bh_socket_t socket)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+int
+os_socket_connect(bh_socket_t socket, const char *addr, int port)
+{}
+
+int
+os_socket_create(bh_socket_t *sock, int tcp_or_udp)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+int
+os_socket_inet_network(const char *cp, uint32 *out)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+int
+os_socket_listen(bh_socket_t socket, int max_client)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+int
+os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+int
+os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+int
+os_socket_shutdown(bh_socket_t socket)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
 #endif

+ 10 - 0
core/shared/platform/windows/win_socket.c

@@ -152,3 +152,13 @@ os_socket_shutdown(bh_socket_t socket)
     shutdown(socket, SD_BOTH);
     return BHT_OK;
 }
+
+int
+os_socket_inet_network(const char *cp, uint32 *out)
+{
+    if (!cp)
+        return BHT_ERROR;
+
+    *out = inet_addr(cp);
+    return BHT_OK;
+}

+ 66 - 0
doc/socket_api.md

@@ -0,0 +1,66 @@
+# How to use Berkeley/Posix Socket APIs in WebAssembly
+
+**_Berkeley sockets_** usually means an API for Internet sockets and Unix domain
+sockets. A socket is an abstract representation of the local endpoint of a
+network communication path.
+
+Currently, WAMR supports a limit set of all well-known functions:
+`accept()`, `bind()`, `connect()`, `listen()`, `recv()`, `send()`, `shutdown()`
+and `socket()`. Users can call those functions in WebAssembly code directly.
+Those WebAssembly socket calls will be dispatched to the imported
+functions and eventually will be implemented by host socket APIs.
+
+This document introduces a way to support _Berkeley/Posix Socket APIs_ in
+WebAssembly code.
+
+## Patch the native code
+
+The first step is to include a header file of the WAMR socket extension in the
+native source code.
+
+```c
+#ifdef __wasi__
+#include <wasi_socket_ext.h>
+#endif
+```
+
+`__wasi__` is a Marco defined by WASI. The host compiler will not enable it.
+
+## CMake files
+
+It is recommended that the project should use CMake as its build system. Use
+[_wasi-sdk_](https://github.com/WebAssembly/wasi-sdk)
+as a toolchain to compile C/C++ to WebAssembly
+
+```bash
+$ cmake -DWASI_SDK_PREFIX=${WASI_SDK_DIR}
+      -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE}
+      -DCMAKE_SYSROOT=${WASI_SYS_ROOT}
+      ..
+```
+
+In the *CMakeLists.txt*, include an extension of socket support and link with it.
+
+```cmake
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake)
+add_executable(socket_example tcp_server.c)
+target_link_libraries(socket_example socket_wasi_ext)
+```
+
+Now, the native code with socket APIs is ready for compilation.
+
+## Run with iwasm
+
+If having the _.wasm_, the last step is to run it with _iwasm_.
+
+The _iwasm_ should be compiled with `WAMR_BUILD_LIBC_WASI=1`. By default, it is
+enabled.
+
+_iwasm_ accepts address ranges via an option, `--addr-pool`, to implement
+the capability control. All IP address the WebAssebmly application may need to `bind()` or `connect()` should be announced first. Every IP address should be in CIRD notation.
+
+```bash
+$ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm
+```
+
+Refer to [socket api sample](../samples/socket-api) for more details.

+ 30 - 3
product-mini/platforms/posix/main.c

@@ -16,8 +16,6 @@
 static int app_argc;
 static char **app_argv;
 
-#define MODULE_PATH ("--module-path=")
-
 /* clang-format off */
 static int
 print_help()
@@ -41,6 +39,10 @@ print_help()
     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=           Grant wasi access to the given network addresses in\n");
+    printf("                         CIRD notation to the program, seperated with ',',\n");
+    printf("                         for example:\n");
+    printf("                           --addr-pool=1.2.3.4/15,2.3.4.5/16\n");
 #endif
 #if WASM_ENABLE_MULTI_MODULE != 0
     printf("  --module-path=         Indicate a module search path. default is current\n"
@@ -244,6 +246,8 @@ main(int argc, char *argv[])
     uint32 dir_list_size = 0;
     const char *env_list[8] = { NULL };
     uint32 env_list_size = 0;
+    const char *addr_pool[8] = { NULL };
+    uint32 addr_pool_size = 0;
 #endif
 #if WASM_ENABLE_DEBUG_INTERP != 0
     char *ip_addr = NULL;
@@ -312,9 +316,30 @@ main(int argc, char *argv[])
                 return print_help();
             }
         }
+        /* TODO: parse the configuration file via --addr-pool-file */
+        else if (!strncmp(argv[0], "--addr-pool=", strlen("--addr-pool="))) {
+            /* like: --addr-pool=100.200.244.255/30 */
+            char *token = NULL;
+
+            if ('\0' == argv[0][12])
+                return print_help();
+
+            token = strtok(argv[0] + strlen("--addr-pool="), ",");
+            while (token) {
+                if (addr_pool_size >= sizeof(addr_pool) / sizeof(char *)) {
+                    printf("Only allow max address number %d\n",
+                           (int)(sizeof(addr_pool) / sizeof(char *)));
+                    return -1;
+                }
+
+                addr_pool[addr_pool_size++] = token;
+                token = strtok(NULL, ";");
+            }
+        }
 #endif /* WASM_ENABLE_LIBC_WASI */
 #if WASM_ENABLE_MULTI_MODULE != 0
-        else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) {
+        else if (!strncmp(argv[0],
+                          "--module-path=", strlen("--module-path="))) {
             module_search_path = handle_module_path(argv[0]);
             if (!strlen(module_search_path)) {
                 return print_help();
@@ -422,6 +447,8 @@ main(int argc, char *argv[])
 #if WASM_ENABLE_LIBC_WASI != 0
     wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0,
                                env_list, env_list_size, argv, argc);
+
+    wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, addr_pool_size);
 #endif
 
     /* instantiate the module */

+ 162 - 0
samples/socket-api/CMakeLists.txt

@@ -0,0 +1,162 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required(VERSION 2.8...3.18)
+project(socket_api_sample)
+
+#######################################
+## Detect toolchain
+#######################################
+message(CHECK_START "Detecting WASI-SDK at /opt/wasi-sdk")
+if(NOT (DEFINED WASI_SDK_DIR OR DEFINED CACHE{WASI_SDK_DIR}))
+  find_path(WASI_SDK_PARENT
+    wasi-sdk
+    PATHS /opt
+    NO_DEFAULT_PATH
+    NO_CMAKE_FIND_ROOT_PATH
+  )
+  if(WASI_SDK_PARENT)
+    set(WASI_SDK_DIR ${WASI_SDK_PARENT}/wasi-sdk)
+  endif()
+endif()
+if(WASI_SDK_DIR)
+  message(CHECK_PASS "found")
+else()
+  message(CHECK_FAIL "not found")
+endif()
+
+if(NOT EXISTS ${WASI_SDK_DIR})
+  message(FATAL_ERROR "Please install WASI-SDK under /opt/wasi-sdk")
+endif()
+
+message(CHECK_START "Detecting WASI_TOOLCHAIN_FILE at ${WASI_SDK_DIR}")
+find_file(WASI_TOOLCHAIN_FILE
+  wasi-sdk.cmake
+  PATHS "${WASI_SDK_DIR}/share/cmake"
+  NO_DEFAULT_PATH
+  NO_CMAKE_FIND_ROOT_PATH
+)
+if(WASI_TOOLCHAIN_FILE)
+  message(CHECK_PASS "found")
+else()
+  message(CHECK_FAIL "not found")
+endif()
+
+if(WASI_TOOLCHAIN_FILE-NOTFOUND)
+  message(FATAL_ERROR "Can not find wasi-sdk.cmake under ${WASI_SDK_DIR}")
+endif()
+
+message(CHECK_START "Detecting WASI_SYS_ROOT at ${WASI_SDK_DIR}")
+find_path(WASI_SYS_ROOT
+  wasi-sysroot
+  PATHS "${WASI_SDK_DIR}/share"
+  NO_DEFAULT_PATH
+  NO_CMAKE_FIND_ROOT_PATH
+)
+if(WASI_SYS_ROOT)
+  message(CHECK_PASS "found")
+  set(WASI_SYS_ROOT ${WASI_SYS_ROOT}/wasi-sysroot)
+else()
+  message(CHECK_FAIL "not found")
+endif()
+
+if(WASI_SYS_ROOT-NOTFOUND)
+  message(FATAL_ERROR "Can not find wasi-sysroot/ under ${WASI_SDK_DIR}")
+endif()
+
+message(STATUS "WASI_SDK_DIR is ${WASI_SDK_DIR}")
+message(STATUS "WASI_TOOLCHAIN_FILE is ${WASI_TOOLCHAIN_FILE}")
+message(STATUS "WASI_SYS_ROOT is ${WASI_SYS_ROOT}")
+
+###############################################################
+## Build socket applications of wasm version and native version
+###############################################################
+include(ExternalProject)
+
+ExternalProject_Add(wasm-app
+  SOURCE_DIR        ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src
+  UPDATE_COMMAND    ""
+  PATCH_COMMAND     ""
+  CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
+                      ${CMAKE_CURRENT_SOURCE_DIR}/../../wamr-sdk/app/libc-builtin-sysroot/include/pthread.h
+                      ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/inc
+                    && ${CMAKE_COMMAND}
+                      -DWASI_SDK_PREFIX=${WASI_SDK_DIR}
+                      -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE}
+                      -DCMAKE_SYSROOT=${WASI_SYS_ROOT}
+                      ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src
+  BUILD_COMMAND     ${CMAKE_COMMAND} --build .
+  INSTALL_COMMAND   ${CMAKE_COMMAND} -E copy
+                      tcp_client.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build
+                      tcp_server.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build
+                      tcp_client.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build
+                      tcp_server.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build
+)
+
+add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c)
+target_link_libraries(tcp_server pthread)
+add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c)
+
+############################################
+## Build iwasm with wasi and pthread support
+############################################
+string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
+if (APPLE)
+  add_definitions(-DBH_PLATFORM_DARWIN)
+endif ()
+
+# Reset linker flags
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
+
+# Set WAMR features
+
+# Set WAMR_BUILD_TARGET, currently values supported:
+# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]",
+# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]"
+if (NOT DEFINED WAMR_BUILD_TARGET)
+  if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
+    set (WAMR_BUILD_TARGET "AARCH64")
+  elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
+    set (WAMR_BUILD_TARGET "RISCV64")
+  elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
+    # Build as X86_64 by default in 64-bit platform
+    set (WAMR_BUILD_TARGET "X86_64")
+  else ()
+    # Build as X86_32 by default in 32-bit platform
+    set (WAMR_BUILD_TARGET "X86_32")
+  endif ()
+endif ()
+
+if (NOT CMAKE_BUILD_TYPE)
+  set (CMAKE_BUILD_TYPE Release)
+endif ()
+
+set(WAMR_BUILD_INTERP 1)
+set(WAMR_BUILD_FAST_INTERP 1)
+set(WAMR_BUILD_AOT 1)
+set(WAMR_BUILD_JIT 0)
+set(WAMR_BUILD_LIBC_BUILTIN 1)
+set(WAMR_BUILD_LIBC_WASI 1)
+set(WAMR_BUILD_LIB_PTHREAD 1)
+
+# compiling and linking flags
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE")
+if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
+  set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
+endif ()
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security")
+
+# build vmlib static lib
+set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
+include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
+add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
+
+# build iwasm
+include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
+set (RUNTIME_SOURCE_ALL
+    ${CMAKE_CURRENT_LIST_DIR}/../../product-mini/platforms/linux/main.c
+    ${UNCOMMON_SHARED_SOURCE}
+)
+add_executable (iwasm ${RUNTIME_SOURCE_ALL})
+target_link_libraries(iwasm vmlib -lpthread -lm)

+ 57 - 0
samples/socket-api/README.md

@@ -0,0 +1,57 @@
+"socket-api" sample introduction
+================================
+
+This sample demonstrates how to use WAMR socket-api to develop wasm network applications.
+Two wasm applications are provided: tcp-server and tcp-client, and this sample demonstrates
+how they communicate with each other.
+
+## Preparation
+
+Please install WASI SDK, download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`.
+And install wabt, download the [wabt release](https://github.com/WebAssembly/wabt/releases) and extract the archive to default path `/opt/wabt`
+
+## Build the sample
+
+```bash
+mkdir build
+cd build
+cmake ..
+make
+```
+
+The file `tcp_server.wasm`, `tcp_client.wasm` and `iwasm` will be created.
+And also file `tcp_server` and `tcp_client` of native version are created.
+
+Note that iwasm is built with libc-wasi and lib-pthread enabled.
+
+## Run workload
+
+Start the tcp server, which opens port 1234 and waits for clients to connect.
+```bash
+cd build
+./iwasm --addr-pool=0.0.0.0/15 tcp_server.wasm
+```
+
+Start the tcp client, which connects the server and receives message.
+```bash
+cd build
+./iwasm --addr-pool=127.0.0.1/15 tcp_client.wasm
+```
+
+The output of client is like:
+```bash
+[Client] Create socket
+[Client] Connect socket
+[Client] Client receive
+[Client] 115 bytes received:
+Buffer recieved:
+Say Hi from the Server
+Say Hi from the Server
+Say Hi from the Server
+Say Hi from the Server
+Say Hi from the Server
+
+[Client] BYE
+```
+
+Refer to [socket api document](../../doc/socket_api.md) for more details.

+ 80 - 0
samples/socket-api/wasm-src/CMakeLists.txt

@@ -0,0 +1,80 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required(VERSION 2.8...3.18)
+project(socket_api_sample_wasm_app)
+
+message(CHECK_START "Detecting WABT")
+if(NOT (DEFINED WABT_DIR OR DEFINED CACHE{WABT_DIR}))
+  find_path(WABT_DIR
+    wabt
+    PATHS /opt
+    NO_DEFAULT_PATH
+    NO_CMAKE_FIND_ROOT_PATH
+  )
+  if(DEFINED WABT_DIR)
+    set(WABT_DIR ${WABT_DIR}/wabt)
+  endif()
+endif()
+if(WABT_DIR)
+  message(CHECK_PASS "found")
+else()
+  message(CHECK_FAIL "not found")
+endif()
+
+message(CHECK_START "Detecting WASM_OBJDUMP at ${WABT_DIR}")
+find_program(WASM_OBJDUMP
+  wasm-objdump
+  PATHS "${WABT_DIR}/bin"
+  NO_DEFAULT_PATH
+  NO_CMAKE_FIND_ROOT_PATH
+)
+if(WASM_OBJDUMP)
+  message(CHECK_PASS "found")
+else()
+  message(CHECK_FAIL "not found")
+endif()
+
+set(SRC ${CMAKE_CURRENT_SOURCE_DIR})
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake)
+
+function(COMPILE_WITH_CLANG SOURCE_FILE)
+  get_filename_component(FILE_NAME ${SOURCE_FILE} NAME_WLE)
+
+  set(WASM_MODULE ${FILE_NAME}.wasm)
+
+  set(MAIN_TARGET_NAME MODULE_${FILE_NAME})
+
+  add_executable(${MAIN_TARGET_NAME} ${SOURCE_FILE})
+  set_target_properties(${MAIN_TARGET_NAME} PROPERTIES OUTPUT_NAME ${WASM_MODULE})
+  target_include_directories(${MAIN_TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/inc)
+  target_compile_options(${MAIN_TARGET_NAME} INTERFACE -pthread)
+  target_link_libraries(${MAIN_TARGET_NAME} socket_wasi_ext)
+  target_link_options(${MAIN_TARGET_NAME} PRIVATE
+    LINKER:--export=__heap_base
+    LINKER:--export=__data_end
+    LINKER:--shared-memory,--max-memory=196608
+    LINKER:--no-check-features
+    LINKER:--allow-undefined
+  )
+
+  if(EXISTS ${WASM_OBJDUMP})
+    message(STATUS "Dumping ${WASM_MODULE}...")
+    set(WASM_DUMP ${WASM_MODULE}.dump)
+    set(DUMP_TARGET_NAME DUMP_${FILE_NAME})
+
+    add_custom_command(OUTPUT ${WASM_DUMP}
+      COMMAND ${WASM_OBJDUMP} -dx ${WASM_MODULE} > ${WASM_DUMP}
+      COMMENT "Dumping ${WASM_MODULE}..."
+      DEPENDS ${MAIN_TARGET_NAME}
+    )
+
+    add_custom_target(${DUMP_TARGET_NAME} ALL
+      DEPENDS ${WASM_DUMP}
+    )
+  endif()
+endfunction()
+
+compile_with_clang(tcp_server.c)
+compile_with_clang(tcp_client.c)

+ 0 - 0
test-tools/build-wasi-sdk/include/.gitkeep → samples/socket-api/wasm-src/inc/.gitkeep


+ 62 - 0
samples/socket-api/wasm-src/tcp_client.c

@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <arpa/inet.h>
+#include <netinet/in.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
+
+int
+main(int argc, char *argv[])
+{
+    int socket_fd, ret, total_size = 0;
+    char buffer[1024] = { 0 };
+    struct sockaddr_in server_address = { 0 };
+
+    printf("[Client] Create socket\n");
+    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+    if (socket_fd == -1) {
+        perror("Create socket failed");
+        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) {
+        perror("Connect failed");
+        close(socket_fd);
+        return EXIT_FAILURE;
+    }
+
+    printf("[Client] Client receive\n");
+    while (1) {
+        ret = recv(socket_fd, buffer + total_size, sizeof(buffer) - total_size,
+                   0);
+        if (ret <= 0)
+            break;
+        total_size += ret;
+    }
+
+    printf("[Client] %d bytes received:\n", total_size);
+    if (total_size > 0) {
+        printf("Buffer recieved:\n%s\n", buffer);
+    }
+
+    close(socket_fd);
+    printf("[Client] BYE \n");
+    return EXIT_SUCCESS;
+}

+ 118 - 0
samples/socket-api/wasm-src/tcp_server.c

@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#ifdef __wasi__
+#include <wasi_socket_ext.h>
+#endif
+
+#define WORKER_NUM 5
+
+void *
+run(void *arg)
+{
+    const char *message = "Say Hi from the Server\n";
+    int new_socket = *(int *)arg;
+    int i;
+
+    printf("[Server] Communicate with the new connection #%u @ %p ..\n",
+           new_socket, (void *)(uintptr_t)pthread_self());
+
+    for (i = 0; i < 5; i++) {
+        if (send(new_socket, message, strlen(message), 0) < 0) {
+            perror("Send failed");
+            break;
+        }
+    }
+
+    printf("[Server] Shuting down the new connection #%u ..\n", new_socket);
+    shutdown(new_socket, SHUT_RDWR);
+
+    return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+    int socket_fd = -1, addrlen = 0;
+    struct sockaddr_in addr = { 0 };
+    unsigned connections = 0;
+    pthread_t workers[WORKER_NUM] = { 0 };
+    int client_sock_fds[WORKER_NUM] = { 0 };
+
+    printf("[Server] Create socket\n");
+    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+    if (socket_fd < 0) {
+        perror("Create socket failed");
+        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;
+    }
+
+    printf("[Server] Listening on socket\n");
+    if (listen(socket_fd, 3) < 0) {
+        perror("Listen failed");
+        goto fail;
+    }
+
+    printf("[Server] Wait for clients to connect ..\n");
+    while (connections < WORKER_NUM) {
+        client_sock_fds[connections] =
+            accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
+        if (client_sock_fds[connections] < 0) {
+            perror("Accept failed");
+            break;
+        }
+
+        printf("[Server] Client connected\n");
+        if (pthread_create(&workers[connections], NULL, run,
+                           &client_sock_fds[connections])) {
+            perror("Create a worker thread failed");
+            shutdown(client_sock_fds[connections], SHUT_RDWR);
+            break;
+        }
+
+        connections++;
+    }
+
+    if (connections == WORKER_NUM) {
+        printf("[Server] Achieve maximum amount of connections\n");
+    }
+
+    for (int i = 0; i < WORKER_NUM; i++) {
+        pthread_join(workers[i], NULL);
+    }
+
+    printf("[Server] Shuting down ..\n");
+    shutdown(socket_fd, SHUT_RDWR);
+    sleep(3);
+    printf("[Server] BYE \n");
+    return EXIT_SUCCESS;
+
+fail:
+    printf("[Server] Shuting down ..\n");
+    if (socket_fd >= 0)
+        close(socket_fd);
+    sleep(3);
+    return EXIT_FAILURE;
+}