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
This commit is contained in:
Wenyong Huang 2022-03-10 15:13:38 +08:00 committed by GitHub
parent 0065743075
commit 9c87a1ee17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2211 additions and 214 deletions

View File

@ -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.

View File

@ -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))

View File

@ -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)

View File

@ -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

View File

@ -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.
*

View File

@ -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];

View File

@ -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)) {

View File

@ -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

View File

@ -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/)

View File

@ -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;
}

View File

@ -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)
{
@ -987,112 +996,277 @@ wasi_random_get(wasm_exec_env_t exec_env, void *buf, uint32 buf_len)
}
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)
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_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;
return __WASI_EINVAL;
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;
/* 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;
iovec = iovec_begin;
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;
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;
}
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;
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;
/* 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;
ciovec = ciovec_begin;
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;
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;
}
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;
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"),
};

View File

@ -13,38 +13,43 @@
extern "C" {
#endif
typedef __wasi_errno_t wasi_errno_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_address_family_t wasi_address_family_t;
typedef __wasi_addr_t wasi_addr_t;
typedef __wasi_advice_t wasi_advice_t;
typedef __wasi_lookupflags_t wasi_lookupflags_t;
typedef __wasi_oflags_t wasi_oflags_t;
typedef __wasi_ciovec_t wasi_ciovec_t;
typedef __wasi_clockid_t wasi_clockid_t;
typedef __wasi_dircookie_t wasi_dircookie_t;
typedef __wasi_filestat_t wasi_filestat_t;
typedef __wasi_fstflags_t wasi_fstflags_t;
typedef __wasi_subscription_t wasi_subscription_t;
typedef __wasi_errno_t wasi_errno_t;
typedef __wasi_event_t wasi_event_t;
typedef __wasi_exitcode_t wasi_exitcode_t;
typedef __wasi_signal_t wasi_signal_t;
typedef __wasi_riflags_t wasi_riflags_t;
typedef __wasi_roflags_t wasi_roflags_t;
typedef __wasi_siflags_t wasi_siflags_t;
typedef __wasi_sdflags_t wasi_sdflags_t;
typedef __wasi_fdflags_t wasi_fdflags_t;
typedef __wasi_fdstat_t wasi_fdstat_t;
typedef __wasi_fd_t wasi_fd_t;
typedef __wasi_filedelta_t wasi_filedelta_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_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_sdflags_t wasi_sdflags_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 */

View File

@ -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)

View File

@ -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.
@ -2715,44 +2716,246 @@ wasmtime_ssp_random_get(void *buf, size_t nbyte)
return 0;
}
__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)
{
__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, fd, __WASI_RIGHT_SOCK_ACCEPT, 0);
if (error != __WASI_ESUCCESS)
return error;
ret = os_socket_accept(fd_number(fo), &new_sock, NULL, NULL);
fd_object_release(fo);
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;
}
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
wasi_ssp_sock_addr_local(
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
struct fd_table *curfds,
#endif
__wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len)
{
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;
}
__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);
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;
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 (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 {
assert(wasi_type == __WASI_FILETYPE_SOCKET_STREAM);
}
// 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_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)
__wasi_fd_t sock, void *buf, size_t buf_len, size_t *recv_len)
{
// 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;
struct fd_object *fo;
__wasi_errno_t error =
fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0);
__wasi_errno_t error;
int ret;
error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0);
if (error != 0) {
return error;
}
ssize_t datalen = recvmsg(fd_number(fo), &hdr, nflags);
ret = os_socket_recv(fd_number(fo), buf, buf_len);
fd_object_release(fo);
if (datalen < 0) {
if (ret == BHT_ERROR) {
return convert_errno(errno);
}
// 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;
*recv_len = (size_t)ret;
return __WASI_ESUCCESS;
}
__wasi_errno_t
@ -2760,34 +2963,25 @@ wasmtime_ssp_sock_send(
#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 sock, const void *buf, size_t buf_len, size_t *sent_len)
{
// Convert input to msghdr.
struct msghdr hdr = {
.msg_iov = (struct iovec *)si_data,
.msg_iovlen = si_data_len,
};
// Attach file descriptors if present.
__wasi_errno_t error;
// Send message.
struct fd_object *fo;
__wasi_errno_t error;
int ret;
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);
fd_object_release(fo);
if (len < 0) {
error = convert_errno(errno);
}
else {
*so_datalen = (size_t)len;
if (error != 0) {
return error;
}
out:
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
@ -2795,34 +2989,22 @@ 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)
{
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 =
fd_object_get(curfds, &fo, sock, __WASI_RIGHT_SOCK_SHUTDOWN, 0);
__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;
}
}

View File

@ -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

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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
doc/socket_api.md Normal file
View File

@ -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.

View File

@ -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 */

View File

@ -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)

View File

@ -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.

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}