mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2024-11-26 15:32:05 +00:00
Merge dev/socket into main (#1393)
Implement more socket APIs, refer to #1336 and below PRs: - Implement wasi_addr_resolve function (#1319) - Fix socket-api byte order issue when host/network order are the same (#1327) - Enhance sock_addr_local syscall (#1320) - Implement sock_addr_remote syscall (#1360) - Add support for IPv6 in WAMR (#1411) - Implement ns lookup allowlist (#1420) - Implement sock_send_to and sock_recv_from system calls (#1457) - Added http downloader and multicast socket options (#1467) - Fix `bind()` calls to receive the correct size of `sockaddr` structure (#1490) - Assert on correct parameters (#1505) - Copy only received bytes from socket recv buffer into the app buffer (#1497) Co-authored-by: Marcin Kolny <mkolny@amazon.com> Co-authored-by: Marcin Kolny <marcin.kolny@gmail.com> Co-authored-by: Callum Macmillan <callumimacmillan@gmail.com>
This commit is contained in:
parent
32d2d16908
commit
78b5c5b484
|
@ -1061,9 +1061,11 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size,
|
|||
module->wasi_args.map_dir_list, module->wasi_args.map_dir_count,
|
||||
module->wasi_args.env, module->wasi_args.env_count,
|
||||
module->wasi_args.addr_pool, module->wasi_args.addr_count,
|
||||
module->wasi_args.argv, module->wasi_args.argc,
|
||||
module->wasi_args.stdio[0], module->wasi_args.stdio[1],
|
||||
module->wasi_args.stdio[2], error_buf, error_buf_size))
|
||||
module->wasi_args.ns_lookup_pool,
|
||||
module->wasi_args.ns_lookup_count, module->wasi_args.argv,
|
||||
module->wasi_args.argc, module->wasi_args.stdio[0],
|
||||
module->wasi_args.stdio[1], module->wasi_args.stdio[2],
|
||||
error_buf, error_buf_size))
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2328,12 +2328,8 @@ wasm_runtime_enlarge_memory(WASMModuleInstanceCommon *module,
|
|||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
|
||||
void
|
||||
wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
|
||||
uint32 dir_count, const char *map_dir_list[],
|
||||
uint32 map_dir_count, const char *env_list[],
|
||||
uint32 env_count, char *argv[], int argc,
|
||||
int stdinfd, int stdoutfd, int stderrfd)
|
||||
static WASIArguments *
|
||||
get_wasi_args_from_module(wasm_module_t module)
|
||||
{
|
||||
WASIArguments *wasi_args = NULL;
|
||||
|
||||
|
@ -2346,6 +2342,18 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
|
|||
wasi_args = &((AOTModule *)module)->wasi_args;
|
||||
#endif
|
||||
|
||||
return wasi_args;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[],
|
||||
uint32 dir_count, const char *map_dir_list[],
|
||||
uint32 map_dir_count, const char *env_list[],
|
||||
uint32 env_count, char *argv[], int argc,
|
||||
int stdinfd, int stdoutfd, int stderrfd)
|
||||
{
|
||||
WASIArguments *wasi_args = get_wasi_args_from_module(module);
|
||||
|
||||
if (wasi_args) {
|
||||
wasi_args->dir_list = dir_list;
|
||||
wasi_args->dir_count = dir_count;
|
||||
|
@ -2376,16 +2384,7 @@ void
|
|||
wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
|
||||
uint32 addr_pool_size)
|
||||
{
|
||||
WASIArguments *wasi_args = NULL;
|
||||
|
||||
#if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0
|
||||
if (module->module_type == Wasm_Module_Bytecode)
|
||||
wasi_args = &((WASMModule *)module)->wasi_args;
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module->module_type == Wasm_Module_AoT)
|
||||
wasi_args = &((AOTModule *)module)->wasi_args;
|
||||
#endif
|
||||
WASIArguments *wasi_args = get_wasi_args_from_module(module);
|
||||
|
||||
if (wasi_args) {
|
||||
wasi_args->addr_pool = addr_pool;
|
||||
|
@ -2393,13 +2392,67 @@ wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module,
|
||||
const char *ns_lookup_pool[],
|
||||
uint32 ns_lookup_pool_size)
|
||||
{
|
||||
WASIArguments *wasi_args = get_wasi_args_from_module(module);
|
||||
|
||||
if (wasi_args) {
|
||||
wasi_args->ns_lookup_pool = ns_lookup_pool;
|
||||
wasi_args->ns_lookup_count = ns_lookup_pool_size;
|
||||
}
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_UVWASI == 0
|
||||
static bool
|
||||
copy_string_array(const char *array[], uint32 array_size, char **buf_ptr,
|
||||
char ***list_ptr, uint64 *out_buf_size)
|
||||
{
|
||||
uint64 buf_size = 0, total_size;
|
||||
uint32 buf_offset = 0, i;
|
||||
char *buf = NULL, **list = NULL;
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
buf_size += strlen(array[i]) + 1;
|
||||
|
||||
/* We add +1 to generate null-terminated array of strings */
|
||||
total_size = sizeof(char *) * (uint64)array_size + 1;
|
||||
if (total_size >= UINT32_MAX
|
||||
|| (total_size > 0 && !(list = wasm_runtime_malloc((uint32)total_size)))
|
||||
|| buf_size >= UINT32_MAX
|
||||
|| (buf_size > 0 && !(buf = wasm_runtime_malloc((uint32)buf_size)))) {
|
||||
|
||||
if (buf)
|
||||
wasm_runtime_free(buf);
|
||||
if (list)
|
||||
wasm_runtime_free(list);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < array_size; i++) {
|
||||
list[i] = buf + buf_offset;
|
||||
bh_strcpy_s(buf + buf_offset, (uint32)buf_size - buf_offset, array[i]);
|
||||
buf_offset += (uint32)(strlen(array[i]) + 1);
|
||||
}
|
||||
list[array_size] = NULL;
|
||||
|
||||
*list_ptr = list;
|
||||
*buf_ptr = buf;
|
||||
if (out_buf_size)
|
||||
*out_buf_size = buf_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
|
||||
const char *dir_list[], uint32 dir_count,
|
||||
const char *map_dir_list[], uint32 map_dir_count,
|
||||
const char *env[], uint32 env_count,
|
||||
const char *addr_pool[], uint32 addr_pool_size,
|
||||
const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
|
||||
char *argv[], uint32 argc, int stdinfd, int stdoutfd,
|
||||
int stderrfd, char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
|
@ -2408,8 +2461,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
|
|||
char **argv_list = NULL;
|
||||
char *env_buf = NULL;
|
||||
char **env_list = NULL;
|
||||
uint64 argv_buf_size = 0, env_buf_size = 0, total_size;
|
||||
uint32 argv_buf_offset = 0, env_buf_offset = 0;
|
||||
char *ns_lookup_buf = NULL;
|
||||
char **ns_lookup_list = NULL;
|
||||
uint64 argv_buf_size = 0, env_buf_size = 0;
|
||||
struct fd_table *curfds = NULL;
|
||||
struct fd_prestats *prestats = NULL;
|
||||
struct argv_environ_values *argv_environ = NULL;
|
||||
|
@ -2443,50 +2497,20 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
|
|||
#endif
|
||||
|
||||
/* process argv[0], trip the path and suffix, only keep the program name */
|
||||
for (i = 0; i < argc; i++)
|
||||
argv_buf_size += strlen(argv[i]) + 1;
|
||||
|
||||
total_size = sizeof(char *) * (uint64)argc;
|
||||
if (total_size >= UINT32_MAX
|
||||
|| (total_size > 0
|
||||
&& !(argv_list = wasm_runtime_malloc((uint32)total_size)))
|
||||
|| argv_buf_size >= UINT32_MAX
|
||||
|| (argv_buf_size > 0
|
||||
&& !(argv_buf = wasm_runtime_malloc((uint32)argv_buf_size)))) {
|
||||
if (!copy_string_array((const char **)argv, argc, &argv_buf, &argv_list,
|
||||
&argv_buf_size)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Init wasi environment failed: allocate memory failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
argv_list[i] = argv_buf + argv_buf_offset;
|
||||
bh_strcpy_s(argv_buf + argv_buf_offset,
|
||||
(uint32)argv_buf_size - argv_buf_offset, argv[i]);
|
||||
argv_buf_offset += (uint32)(strlen(argv[i]) + 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < env_count; i++)
|
||||
env_buf_size += strlen(env[i]) + 1;
|
||||
|
||||
total_size = sizeof(char *) * (uint64)env_count;
|
||||
if (total_size >= UINT32_MAX
|
||||
|| (total_size > 0
|
||||
&& !(env_list = wasm_runtime_malloc((uint32)total_size)))
|
||||
|| env_buf_size >= UINT32_MAX
|
||||
|| (env_buf_size > 0
|
||||
&& !(env_buf = wasm_runtime_malloc((uint32)env_buf_size)))) {
|
||||
if (!copy_string_array(env, env_count, &env_buf, &env_list,
|
||||
&env_buf_size)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Init wasi environment failed: allocate memory failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < env_count; i++) {
|
||||
env_list[i] = env_buf + env_buf_offset;
|
||||
bh_strcpy_s(env_buf + env_buf_offset,
|
||||
(uint32)env_buf_size - env_buf_offset, env[i]);
|
||||
env_buf_offset += (uint32)(strlen(env[i]) + 1);
|
||||
}
|
||||
|
||||
if (!(curfds = wasm_runtime_malloc(sizeof(struct fd_table)))
|
||||
|| !(prestats = wasm_runtime_malloc(sizeof(struct fd_prestats)))
|
||||
|| !(argv_environ =
|
||||
|
@ -2588,6 +2612,13 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
|
|||
}
|
||||
}
|
||||
|
||||
if (!copy_string_array(ns_lookup_pool, ns_lookup_pool_size, &ns_lookup_buf,
|
||||
&ns_lookup_list, NULL)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"Init wasi environment failed: allocate memory failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wasi_ctx->curfds = curfds;
|
||||
wasi_ctx->prestats = prestats;
|
||||
wasi_ctx->argv_environ = argv_environ;
|
||||
|
@ -2596,6 +2627,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
|
|||
wasi_ctx->argv_list = argv_list;
|
||||
wasi_ctx->env_buf = env_buf;
|
||||
wasi_ctx->env_list = env_list;
|
||||
wasi_ctx->ns_lookup_buf = ns_lookup_buf;
|
||||
wasi_ctx->ns_lookup_list = ns_lookup_list;
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -2624,6 +2657,10 @@ fail:
|
|||
wasm_runtime_free(env_buf);
|
||||
if (env_list)
|
||||
wasm_runtime_free(env_list);
|
||||
if (ns_lookup_buf)
|
||||
wasm_runtime_free(ns_lookup_buf);
|
||||
if (ns_lookup_list)
|
||||
wasm_runtime_free(ns_lookup_list);
|
||||
return false;
|
||||
}
|
||||
#else /* else of WASM_ENABLE_UVWASI == 0 */
|
||||
|
@ -2675,6 +2712,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
|
|||
const char *map_dir_list[], uint32 map_dir_count,
|
||||
const char *env[], uint32 env_count,
|
||||
const char *addr_pool[], uint32 addr_pool_size,
|
||||
const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
|
||||
char *argv[], uint32 argc, int stdinfd, int stdoutfd,
|
||||
int stderrfd, char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
|
@ -2851,6 +2889,11 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst)
|
|||
wasm_runtime_free(wasi_ctx->env_buf);
|
||||
if (wasi_ctx->env_list)
|
||||
wasm_runtime_free(wasi_ctx->env_list);
|
||||
if (wasi_ctx->ns_lookup_buf)
|
||||
wasm_runtime_free(wasi_ctx->ns_lookup_buf);
|
||||
if (wasi_ctx->ns_lookup_list)
|
||||
wasm_runtime_free(wasi_ctx->ns_lookup_list);
|
||||
|
||||
wasm_runtime_free(wasi_ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -363,6 +363,8 @@ typedef struct WASIContext {
|
|||
struct fd_prestats *prestats;
|
||||
struct argv_environ_values *argv_environ;
|
||||
struct addr_pool *addr_pool;
|
||||
char *ns_lookup_buf;
|
||||
char **ns_lookup_list;
|
||||
char *argv_buf;
|
||||
char **argv_list;
|
||||
char *env_buf;
|
||||
|
@ -775,6 +777,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
|
|||
const char *map_dir_list[], uint32 map_dir_count,
|
||||
const char *env[], uint32 env_count,
|
||||
const char *addr_pool[], uint32 addr_pool_size,
|
||||
const char *ns_lookup_pool[], uint32 ns_lookup_pool_size,
|
||||
char *argv[], uint32 argc, int stdinfd, int stdoutfd,
|
||||
int stderrfd, char *error_buf, uint32 error_buf_size);
|
||||
|
||||
|
@ -791,6 +794,11 @@ wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst);
|
|||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
|
||||
uint32 addr_pool_size);
|
||||
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module,
|
||||
const char *ns_lookup_pool[],
|
||||
uint32 ns_lookup_pool_size);
|
||||
#endif /* end of WASM_ENABLE_LIBC_WASI */
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
|
|
|
@ -376,6 +376,10 @@ WASM_RUNTIME_API_EXTERN void
|
|||
wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
|
||||
uint32_t addr_pool_size);
|
||||
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module, const char *ns_lookup_pool[],
|
||||
uint32_t ns_lookup_pool_size);
|
||||
|
||||
/**
|
||||
* Instantiate a WASM module.
|
||||
*
|
||||
|
|
|
@ -321,6 +321,8 @@ typedef struct WASIArguments {
|
|||
/* in CIDR noation */
|
||||
const char **addr_pool;
|
||||
uint32 addr_count;
|
||||
const char **ns_lookup_pool;
|
||||
uint32 ns_lookup_count;
|
||||
char **argv;
|
||||
uint32 argc;
|
||||
int stdio[3];
|
||||
|
|
|
@ -1701,9 +1701,11 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
|
|||
module->wasi_args.map_dir_list, module->wasi_args.map_dir_count,
|
||||
module->wasi_args.env, module->wasi_args.env_count,
|
||||
module->wasi_args.addr_pool, module->wasi_args.addr_count,
|
||||
module->wasi_args.argv, module->wasi_args.argc,
|
||||
module->wasi_args.stdio[0], module->wasi_args.stdio[1],
|
||||
module->wasi_args.stdio[2], error_buf, error_buf_size)) {
|
||||
module->wasi_args.ns_lookup_pool,
|
||||
module->wasi_args.ns_lookup_count, module->wasi_args.argv,
|
||||
module->wasi_args.argc, module->wasi_args.stdio[0],
|
||||
module->wasi_args.stdio[1], module->wasi_args.stdio[2],
|
||||
error_buf, error_buf_size)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ wasm_create_gdbserver(const char *host, int32 *port)
|
|||
|
||||
memset(server->receive_ctx, 0, sizeof(rsp_recv_context_t));
|
||||
|
||||
if (0 != os_socket_create(&listen_fd, 1)) {
|
||||
if (0 != os_socket_create(&listen_fd, true, true)) {
|
||||
LOG_ERROR("wasm gdb server error: create socket failed");
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef _WASI_SOCKET_EXT_H_
|
||||
#define _WASI_SOCKET_EXT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -20,7 +21,12 @@ typedef uint16_t __wasi_ip_port_t;
|
|||
|
||||
typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t;
|
||||
|
||||
/* n0.n1.n2.n3 */
|
||||
/*
|
||||
n0.n1.n2.n3
|
||||
Example:
|
||||
IP Address: 127.0.0.1
|
||||
Structure: {n0: 127, n1: 0, n2: 0, n3: 1}
|
||||
*/
|
||||
typedef struct __wasi_addr_ip4_t {
|
||||
uint8_t n0;
|
||||
uint8_t n1;
|
||||
|
@ -30,9 +36,18 @@ typedef struct __wasi_addr_ip4_t {
|
|||
|
||||
typedef struct __wasi_addr_ip4_port_t {
|
||||
__wasi_addr_ip4_t addr;
|
||||
__wasi_ip_port_t port;
|
||||
__wasi_ip_port_t port; /* host byte order */
|
||||
} __wasi_addr_ip4_port_t;
|
||||
|
||||
/*
|
||||
n0:n1:n2:n3:h0:h1:h2:h3, each 16bit value uses host byte order
|
||||
Example (little-endian system)
|
||||
IP Address fe80::3ba2:893b:4be0:e3dd
|
||||
Structure: {
|
||||
n0: 0xfe80, n1:0x0, n2: 0x0, n3: 0x0,
|
||||
h0: 0x3ba2, h1: 0x893b, h2: 0x4be0, h3: 0xe3dd
|
||||
}
|
||||
*/
|
||||
typedef struct __wasi_addr_ip6_t {
|
||||
uint16_t n0;
|
||||
uint16_t n1;
|
||||
|
@ -46,9 +61,17 @@ typedef struct __wasi_addr_ip6_t {
|
|||
|
||||
typedef struct __wasi_addr_ip6_port_t {
|
||||
__wasi_addr_ip6_t addr;
|
||||
__wasi_ip_port_t port;
|
||||
__wasi_ip_port_t port; /* host byte order */
|
||||
} __wasi_addr_ip6_port_t;
|
||||
|
||||
typedef struct __wasi_addr_ip_t {
|
||||
__wasi_addr_type_t kind;
|
||||
union {
|
||||
__wasi_addr_ip4_t ip4;
|
||||
__wasi_addr_ip6_t ip6;
|
||||
} addr;
|
||||
} __wasi_addr_ip_t;
|
||||
|
||||
typedef struct __wasi_addr_t {
|
||||
__wasi_addr_type_t kind;
|
||||
union {
|
||||
|
@ -59,6 +82,18 @@ typedef struct __wasi_addr_t {
|
|||
|
||||
typedef enum { INET4 = 0, INET6 } __wasi_address_family_t;
|
||||
|
||||
typedef struct __wasi_addr_info_t {
|
||||
__wasi_addr_t addr;
|
||||
__wasi_sock_type_t type;
|
||||
} __wasi_addr_info_t;
|
||||
|
||||
typedef struct __wasi_addr_info_hints_t {
|
||||
__wasi_sock_type_t type;
|
||||
__wasi_address_family_t family;
|
||||
// this is to workaround lack of optional parameters
|
||||
uint8_t hints_enabled;
|
||||
} __wasi_addr_info_hints_t;
|
||||
|
||||
#ifdef __wasi__
|
||||
/**
|
||||
* Reimplement below POSIX APIs with __wasi_sock_XXX functions.
|
||||
|
@ -67,6 +102,43 @@ typedef enum { INET4 = 0, INET6 } __wasi_address_family_t;
|
|||
* <sys/socket.h>
|
||||
* <sys/types.h>
|
||||
*/
|
||||
#define SO_REUSEADDR 2
|
||||
#define SO_BROADCAST 6
|
||||
#define SO_SNDBUF 7
|
||||
#define SO_RCVBUF 8
|
||||
#define SO_KEEPALIVE 9
|
||||
#define SO_LINGER 13
|
||||
#define SO_REUSEPORT 15
|
||||
#define SO_RCVTIMEO 20
|
||||
#define SO_SNDTIMEO 21
|
||||
|
||||
#define TCP_NODELAY 1
|
||||
#define TCP_KEEPIDLE 4
|
||||
#define TCP_KEEPINTVL 5
|
||||
#define TCP_QUICKACK 12
|
||||
#define TCP_FASTOPEN_CONNECT 30
|
||||
|
||||
#define IP_TTL 2
|
||||
#define IP_MULTICAST_TTL 33
|
||||
#define IP_MULTICAST_LOOP 34
|
||||
#define IP_ADD_MEMBERSHIP 35
|
||||
#define IP_DROP_MEMBERSHIP 36
|
||||
|
||||
#define IPV6_MULTICAST_LOOP 19
|
||||
#define IPV6_JOIN_GROUP 20
|
||||
#define IPV6_LEAVE_GROUP 21
|
||||
#define IPV6_V6ONLY 26
|
||||
|
||||
struct addrinfo {
|
||||
int ai_flags; /* Input flags. */
|
||||
int ai_family; /* Protocol family for socket. */
|
||||
int ai_socktype; /* Socket type. */
|
||||
int ai_protocol; /* Protocol for socket. */
|
||||
socklen_t ai_addrlen; /* Length of socket address. */
|
||||
struct sockaddr *ai_addr; /* Socket address for socket. */
|
||||
char *ai_canonname; /* Canonical name for service location. */
|
||||
struct addrinfo *ai_next; /* Pointer to next in list. */
|
||||
};
|
||||
|
||||
int
|
||||
accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
@ -86,8 +158,37 @@ recvmsg(int sockfd, struct msghdr *msg, int flags);
|
|||
ssize_t
|
||||
sendmsg(int sockfd, const struct msghdr *msg, int flags);
|
||||
|
||||
ssize_t
|
||||
sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
|
||||
ssize_t
|
||||
recvfrom(int sockfd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol);
|
||||
|
||||
int
|
||||
getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
int
|
||||
getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
int
|
||||
getsockopt(int sockfd, int level, int optname, void *__restrict optval,
|
||||
socklen_t *__restrict optlen);
|
||||
|
||||
int
|
||||
setsockopt(int sockfd, int level, int optname, const void *optval,
|
||||
socklen_t optlen);
|
||||
|
||||
int
|
||||
getaddrinfo(const char *node, const char *service, const struct addrinfo *hints,
|
||||
struct addrinfo **res);
|
||||
|
||||
void
|
||||
freeaddrinfo(struct addrinfo *res);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -115,16 +216,15 @@ __wasi_sock_accept(__wasi_fd_t fd, __wasi_fd_t *fd_new)
|
|||
* either IP4 or IP6.
|
||||
*/
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2)
|
||||
__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_addr_local")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_addr_local(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len)
|
||||
__wasi_sock_addr_local(__wasi_fd_t fd, __wasi_addr_t *addr)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_local(
|
||||
(int32_t)fd, (int32_t)buf, (int32_t)buf_len);
|
||||
(int32_t)fd, (int32_t)addr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,43 +236,49 @@ __wasi_sock_addr_local(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len)
|
|||
* either IP4 or IP6.
|
||||
*/
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2)
|
||||
__imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_addr_remote")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_addr_remote(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len)
|
||||
__wasi_sock_addr_remote(__wasi_fd_t fd, __wasi_addr_t *addr)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_remote(
|
||||
(int32_t)fd, (int32_t)buf, (int32_t)buf_len);
|
||||
(int32_t)fd, (int32_t)addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a hostname and a port to one or more IP addresses. Port is optional
|
||||
* and you can pass 0 (zero) in most cases, it is used a hint for protocol.
|
||||
* Resolve a hostname and a service to one or more IP addresses. Service is
|
||||
* optional and you can pass empty string in most cases, it is used as a hint
|
||||
* for protocol.
|
||||
*
|
||||
* Note: This is similar to `getaddrinfo` in POSIX
|
||||
*
|
||||
* When successful, the contents of the output buffer consist of a sequence of
|
||||
* IPv4 and/or IPv6 addresses. Each address entry consists of a addr_t object.
|
||||
* IPv4 and/or IPv6 addresses. Each address entry consists of a wasi_addr_t
|
||||
* object.
|
||||
*
|
||||
* This function fills the output buffer as much as possible, potentially
|
||||
* truncating the last address entry. It is advisable that the buffer is
|
||||
* This function fills the output buffer as much as possible, truncating the
|
||||
* entries that didn't fit into the buffer. A number of available addresses
|
||||
* will be returned through the last parameter.
|
||||
*/
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_addr_resolve(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2, int32_t arg3,
|
||||
int32_t arg4)
|
||||
__imported_wasi_snapshot_preview1_sock_addr_resolve(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2, int32_t arg3,
|
||||
int32_t arg4, int32_t arg5)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("addr_resolve")));
|
||||
__import_name__("sock_addr_resolve")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_addr_resolve(__wasi_fd_t fd, const char *host, __wasi_ip_port_t port,
|
||||
uint8_t *buf, __wasi_size_t size)
|
||||
__wasi_sock_addr_resolve(const char *host, const char *service,
|
||||
__wasi_addr_info_hints_t *hints,
|
||||
__wasi_addr_info_t *addr_info,
|
||||
__wasi_size_t addr_info_size,
|
||||
__wasi_size_t *max_info_size)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_addr_resolve(
|
||||
(int32_t)fd, (int32_t)host, (int32_t)port, (int32_t)buf, (int32_t)size);
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_resolve(
|
||||
(int32_t)host, (int32_t)service, (int32_t)hints, (int32_t)addr_info,
|
||||
(int32_t)addr_info_size, (int32_t)max_info_size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,6 +297,48 @@ __wasi_sock_bind(__wasi_fd_t fd, __wasi_addr_t *addr)
|
|||
(int32_t)fd, (int32_t)addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data to a specific target
|
||||
* Note: This is similar to `sendto` in POSIX
|
||||
*/
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_send_to(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2, int32_t arg3,
|
||||
int32_t arg4, int32_t arg5)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_send_to")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_send_to(__wasi_fd_t fd, const __wasi_ciovec_t *si_data,
|
||||
uint32_t si_data_len, __wasi_siflags_t si_flags,
|
||||
const __wasi_addr_t *dest_addr, uint32_t *so_data_len)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_send_to(
|
||||
(int32_t)fd, (int32_t)si_data, (int32_t)si_data_len, (int32_t)si_flags,
|
||||
(uint32_t)dest_addr, (uint32_t)so_data_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives data from a socket
|
||||
* Note: This is similar to `recvfrom` in POSIX
|
||||
*/
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_recv_from(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2, int32_t arg3,
|
||||
int32_t arg4, int32_t arg5)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_recv_from")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_recv_from(__wasi_fd_t fd, __wasi_ciovec_t *ri_data,
|
||||
uint32_t ri_data_len, __wasi_riflags_t ri_flags,
|
||||
__wasi_addr_t *src_addr, uint32_t *ro_data_len)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_recv_from(
|
||||
(int32_t)fd, (int32_t)ri_data, (int32_t)ri_data_len, (int32_t)ri_flags,
|
||||
(uint32_t)src_addr, (uint32_t)ro_data_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a socket (this is an alias for `fd_close`)
|
||||
* Note: This is similar to `close` in POSIX.
|
||||
|
@ -252,7 +400,7 @@ __imported_wasi_snapshot_preview1_sock_get_reuse_addr(int32_t arg0,
|
|||
__import_name__("sock_get_reuse_addr")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_reuse_addr(__wasi_fd_t fd, uint8_t *reuse)
|
||||
__wasi_sock_get_reuse_addr(__wasi_fd_t fd, bool *reuse)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_reuse_addr((int32_t)fd,
|
||||
|
@ -270,7 +418,7 @@ __imported_wasi_snapshot_preview1_sock_get_reuse_port(int32_t arg0,
|
|||
__import_name__("sock_get_reuse_port")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_reuse_port(__wasi_fd_t fd, int8_t *reuse)
|
||||
__wasi_sock_get_reuse_port(__wasi_fd_t fd, bool *reuse)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_reuse_port((int32_t)fd,
|
||||
|
@ -367,7 +515,7 @@ __imported_wasi_snapshot_preview1_sock_set_reuse_addr(int32_t arg0,
|
|||
__import_name__("sock_set_reuse_addr")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_reuse_addr(__wasi_fd_t fd, uint8_t reuse)
|
||||
__wasi_sock_set_reuse_addr(__wasi_fd_t fd, bool reuse)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_reuse_addr((int32_t)fd,
|
||||
|
@ -385,7 +533,7 @@ __imported_wasi_snapshot_preview1_sock_set_reuse_port(int32_t arg0,
|
|||
__import_name__("sock_set_reuse_port")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_reuse_port(__wasi_fd_t fd, uint8_t reuse)
|
||||
__wasi_sock_set_reuse_port(__wasi_fd_t fd, bool reuse)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_reuse_port((int32_t)fd,
|
||||
|
@ -397,17 +545,432 @@ __wasi_sock_set_reuse_port(__wasi_fd_t fd, uint8_t reuse)
|
|||
* Note: This is similar to `setsockopt` in POSIX for SO_SNDBUF
|
||||
*/
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_send_buf_size(int32_t arg0)
|
||||
__imported_wasi_snapshot_preview1_sock_set_send_buf_size(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_send_buf_size")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_send_buf_size(__wasi_fd_t fd)
|
||||
__wasi_sock_set_send_buf_size(__wasi_fd_t fd, __wasi_size_t buf_len)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_send_buf_size((int32_t)fd);
|
||||
__imported_wasi_snapshot_preview1_sock_set_send_buf_size(
|
||||
(int32_t)fd, (int32_t)buf_len);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_recv_timeout(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_recv_timeout")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_recv_timeout(__wasi_fd_t fd, uint64_t *timeout_us)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_recv_timeout(
|
||||
(int32_t)fd, (int32_t)timeout_us);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_recv_timeout(int32_t arg0,
|
||||
int64_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_recv_timeout")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_recv_timeout(__wasi_fd_t fd, uint64_t timeout_us)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_recv_timeout(
|
||||
(int32_t)fd, (int64_t)timeout_us);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_send_timeout(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_send_timeout")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_send_timeout(__wasi_fd_t fd, uint64_t *timeout_us)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_send_timeout(
|
||||
(int32_t)fd, (int32_t)timeout_us);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_send_timeout(int32_t arg0,
|
||||
int64_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_send_timeout")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_send_timeout(__wasi_fd_t fd, uint64_t timeout_us)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_send_timeout(
|
||||
(int32_t)fd, (int64_t)timeout_us);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_keep_alive(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_keep_alive")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_keep_alive(__wasi_fd_t fd, bool option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_keep_alive((int32_t)fd,
|
||||
(int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_keep_alive(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_keep_alive")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_keep_alive(__wasi_fd_t fd, bool *option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_keep_alive((int32_t)fd,
|
||||
(int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_linger(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_linger")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_linger(__wasi_fd_t fd, bool is_enabled, int linger_s)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_linger(
|
||||
(int32_t)fd, (int32_t)is_enabled, (int32_t)linger_s);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_linger(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_linger")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_linger(__wasi_fd_t fd, bool *is_enabled, int *linger_s)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_linger(
|
||||
(int32_t)fd, (int32_t)is_enabled, (int32_t)linger_s);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_keep_idle(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_tcp_keep_idle")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_tcp_keep_idle(__wasi_fd_t fd, uint32_t time_s)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_keep_idle(
|
||||
(int32_t)fd, (int32_t)time_s);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_keep_idle(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_tcp_keep_idle")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_tcp_keep_idle(__wasi_fd_t fd, uint32_t *time_s)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_keep_idle(
|
||||
(int32_t)fd, (int32_t)time_s);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_keep_intvl(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_tcp_keep_intvl")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_tcp_keep_intvl(__wasi_fd_t fd, uint32_t time_s)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_keep_intvl(
|
||||
(int32_t)fd, (int32_t)time_s);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_keep_intvl(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_tcp_keep_intvl")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_tcp_keep_intvl(__wasi_fd_t fd, uint32_t *time_s)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_keep_intvl(
|
||||
(int32_t)fd, (int32_t)time_s);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_fastopen_connect(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_tcp_fastopen_connect")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_tcp_fastopen_connect(__wasi_fd_t fd, bool option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_fastopen_connect(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_fastopen_connect(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_tcp_fastopen_connect")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_tcp_fastopen_connect(__wasi_fd_t fd, bool *option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_fastopen_connect(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_multicast_loop(int32_t arg0,
|
||||
int32_t arg1,
|
||||
int32_t arg2)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_ip_multicast_loop")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_ip_multicast_loop(__wasi_fd_t fd, bool ipv6, bool option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_multicast_loop(
|
||||
(int32_t)fd, (int32_t)ipv6, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_ip_multicast_loop(int32_t arg0,
|
||||
int32_t arg1,
|
||||
int32_t arg2)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_ip_multicast_loop")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_ip_multicast_loop(__wasi_fd_t fd, bool ipv6, bool *option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_ip_multicast_loop(
|
||||
(int32_t)fd, (int32_t)ipv6, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_multicast_ttl(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_ip_multicast_ttl")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_ip_multicast_ttl(__wasi_fd_t fd, uint8_t option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_multicast_ttl(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_ip_multicast_ttl(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_ip_multicast_ttl")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_ip_multicast_ttl(__wasi_fd_t fd, uint8_t *option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_ip_multicast_ttl(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_add_membership(int32_t arg0,
|
||||
int32_t arg1,
|
||||
int32_t arg2)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_ip_add_membership")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_ip_add_membership(__wasi_fd_t fd,
|
||||
__wasi_addr_ip_t *imr_multiaddr,
|
||||
uint32_t imr_interface)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_add_membership(
|
||||
(int32_t)fd, (int32_t)imr_multiaddr, (int32_t)imr_interface);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_drop_membership(int32_t arg0,
|
||||
int32_t arg1,
|
||||
int32_t arg2)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_ip_drop_membership")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_ip_drop_membership(__wasi_fd_t fd,
|
||||
__wasi_addr_ip_t *imr_multiaddr,
|
||||
uint32_t imr_interface)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_drop_membership(
|
||||
(int32_t)fd, (int32_t)imr_multiaddr, (int32_t)imr_interface);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_broadcast(int32_t arg0, int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_broadcast")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_broadcast(__wasi_fd_t fd, bool option)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_broadcast(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_broadcast(int32_t arg0, int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_broadcast")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_broadcast(__wasi_fd_t fd, bool *option)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_broadcast(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_no_delay(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_tcp_no_delay")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_tcp_no_delay(__wasi_fd_t fd, bool option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_no_delay(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_no_delay(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_tcp_no_delay")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_tcp_no_delay(__wasi_fd_t fd, bool *option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_no_delay(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_quick_ack(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_tcp_quick_ack")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_tcp_quick_ack(__wasi_fd_t fd, bool option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_set_tcp_quick_ack(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_quick_ack(int32_t arg0,
|
||||
int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_tcp_quick_ack")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_tcp_quick_ack(__wasi_fd_t fd, bool *option)
|
||||
{
|
||||
return (__wasi_errno_t)
|
||||
__imported_wasi_snapshot_preview1_sock_get_tcp_quick_ack(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_ip_ttl(int32_t arg0, int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_ip_ttl")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_ip_ttl(__wasi_fd_t fd, uint8_t option)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_ip_ttl(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_ip_ttl(int32_t arg0, int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_ip_ttl")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_ip_ttl(__wasi_fd_t fd, uint8_t *option)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_ip_ttl(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_set_ipv6_only(int32_t arg0, int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_set_ipv6_only")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_set_ipv6_only(__wasi_fd_t fd, bool option)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_ipv6_only(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__imported_wasi_snapshot_preview1_sock_get_ipv6_only(int32_t arg0, int32_t arg1)
|
||||
__attribute__((__import_module__("wasi_snapshot_preview1"),
|
||||
__import_name__("sock_get_ipv6_only")));
|
||||
|
||||
static inline __wasi_errno_t
|
||||
__wasi_sock_get_ipv6_only(__wasi_fd_t fd, bool *option)
|
||||
{
|
||||
return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_ipv6_only(
|
||||
(int32_t)fd, (int32_t)option);
|
||||
}
|
||||
/**
|
||||
* TODO: modify recv() and send()
|
||||
* since don't want to re-compile the wasi-libc,
|
||||
|
|
|
@ -18,16 +18,44 @@
|
|||
return -1; \
|
||||
}
|
||||
|
||||
static void
|
||||
ipv4_addr_to_wasi_ip4_addr(uint32_t addr_num, __wasi_addr_ip4_t *out)
|
||||
{
|
||||
addr_num = ntohl(addr_num);
|
||||
out->n0 = (addr_num & 0xFF000000) >> 24;
|
||||
out->n1 = (addr_num & 0x00FF0000) >> 16;
|
||||
out->n2 = (addr_num & 0x0000FF00) >> 8;
|
||||
out->n3 = (addr_num & 0x000000FF);
|
||||
}
|
||||
|
||||
/* addr_num and port are in network order */
|
||||
static void
|
||||
ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out)
|
||||
{
|
||||
out->kind = IPv4;
|
||||
out->addr.ip4.port = ntohs(port);
|
||||
out->addr.ip4.addr.n3 = (addr_num & 0xFF000000) >> 24;
|
||||
out->addr.ip4.addr.n2 = (addr_num & 0x00FF0000) >> 16;
|
||||
out->addr.ip4.addr.n1 = (addr_num & 0x0000FF00) >> 8;
|
||||
out->addr.ip4.addr.n0 = (addr_num & 0x000000FF);
|
||||
ipv4_addr_to_wasi_ip4_addr(addr_num, &(out->addr.ip4.addr));
|
||||
}
|
||||
|
||||
static void
|
||||
ipv6_addr_to_wasi_ipv6_addr(uint16_t *addr, __wasi_addr_ip6_t *out)
|
||||
{
|
||||
out->n0 = ntohs(addr[0]);
|
||||
out->n1 = ntohs(addr[1]);
|
||||
out->n2 = ntohs(addr[2]);
|
||||
out->n3 = ntohs(addr[3]);
|
||||
out->h0 = ntohs(addr[4]);
|
||||
out->h1 = ntohs(addr[5]);
|
||||
out->h2 = ntohs(addr[6]);
|
||||
out->h3 = ntohs(addr[7]);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv6_addr_to_wasi_addr(uint16_t *addr, uint16_t port, __wasi_addr_t *out)
|
||||
{
|
||||
out->kind = IPv6;
|
||||
out->addr.ip6.port = ntohs(port);
|
||||
ipv6_addr_to_wasi_ipv6_addr(addr, &(out->addr.ip6.addr));
|
||||
}
|
||||
|
||||
static __wasi_errno_t
|
||||
|
@ -36,15 +64,17 @@ sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen,
|
|||
{
|
||||
__wasi_errno_t ret = __WASI_ERRNO_SUCCESS;
|
||||
if (AF_INET == sock_addr->sa_family) {
|
||||
assert(sizeof(struct sockaddr_in) == addrlen);
|
||||
assert(sizeof(struct sockaddr_in) <= addrlen);
|
||||
|
||||
ipv4_addr_to_wasi_addr(
|
||||
((struct sockaddr_in *)sock_addr)->sin_addr.s_addr,
|
||||
((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr);
|
||||
}
|
||||
else if (AF_INET6 == sock_addr->sa_family) {
|
||||
// TODO: IPV6
|
||||
ret = __WASI_ERRNO_AFNOSUPPORT;
|
||||
assert(sizeof(struct sockaddr_in6) <= addrlen);
|
||||
ipv6_addr_to_wasi_addr(
|
||||
(uint16_t *)((struct sockaddr_in6 *)sock_addr)->sin6_addr.s6_addr,
|
||||
((struct sockaddr_in6 *)sock_addr)->sin6_port, wasi_addr);
|
||||
}
|
||||
else {
|
||||
ret = __WASI_ERRNO_AFNOSUPPORT;
|
||||
|
@ -54,38 +84,52 @@ sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen,
|
|||
}
|
||||
|
||||
static __wasi_errno_t
|
||||
sock_addr_remote(__wasi_fd_t fd, struct sockaddr *sock_addr, socklen_t *addrlen)
|
||||
wasi_addr_to_sockaddr(const __wasi_addr_t *wasi_addr,
|
||||
struct sockaddr *sock_addr, socklen_t *addrlen)
|
||||
{
|
||||
__wasi_addr_t wasi_addr = { 0 };
|
||||
__wasi_errno_t error;
|
||||
switch (wasi_addr->kind) {
|
||||
case IPv4:
|
||||
{
|
||||
struct sockaddr_in sock_addr_in = { 0 };
|
||||
uint32_t s_addr;
|
||||
|
||||
error =
|
||||
__wasi_sock_addr_remote(fd, (uint8_t *)&wasi_addr, sizeof(wasi_addr));
|
||||
if (__WASI_ERRNO_SUCCESS != error) {
|
||||
return error;
|
||||
s_addr = (wasi_addr->addr.ip4.addr.n0 << 24)
|
||||
| (wasi_addr->addr.ip4.addr.n1 << 16)
|
||||
| (wasi_addr->addr.ip4.addr.n2 << 8)
|
||||
| wasi_addr->addr.ip4.addr.n3;
|
||||
|
||||
sock_addr_in.sin_family = AF_INET;
|
||||
sock_addr_in.sin_addr.s_addr = htonl(s_addr);
|
||||
sock_addr_in.sin_port = htons(wasi_addr->addr.ip4.port);
|
||||
memcpy(sock_addr, &sock_addr_in, sizeof(sock_addr_in));
|
||||
|
||||
*addrlen = sizeof(sock_addr_in);
|
||||
break;
|
||||
}
|
||||
case IPv6:
|
||||
{
|
||||
struct sockaddr_in6 sock_addr_in6 = { 0 };
|
||||
uint16_t *addr_buf = (uint16_t *)sock_addr_in6.sin6_addr.s6_addr;
|
||||
|
||||
addr_buf[0] = htons(wasi_addr->addr.ip6.addr.n0);
|
||||
addr_buf[1] = htons(wasi_addr->addr.ip6.addr.n1);
|
||||
addr_buf[2] = htons(wasi_addr->addr.ip6.addr.n2);
|
||||
addr_buf[3] = htons(wasi_addr->addr.ip6.addr.n3);
|
||||
addr_buf[4] = htons(wasi_addr->addr.ip6.addr.h0);
|
||||
addr_buf[5] = htons(wasi_addr->addr.ip6.addr.h1);
|
||||
addr_buf[6] = htons(wasi_addr->addr.ip6.addr.h2);
|
||||
addr_buf[7] = htons(wasi_addr->addr.ip6.addr.h3);
|
||||
|
||||
sock_addr_in6.sin6_family = AF_INET6;
|
||||
sock_addr_in6.sin6_port = htons(wasi_addr->addr.ip6.port);
|
||||
memcpy(sock_addr, &sock_addr_in6, sizeof(sock_addr_in6));
|
||||
|
||||
*addrlen = sizeof(sock_addr_in6);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return __WASI_ERRNO_AFNOSUPPORT;
|
||||
}
|
||||
|
||||
if (IPv4 == wasi_addr.kind) {
|
||||
struct sockaddr_in sock_addr_in = { 0 };
|
||||
|
||||
sock_addr_in.sin_family = AF_INET;
|
||||
sock_addr_in.sin_addr.s_addr = (wasi_addr.addr.ip4.addr.n3 << 24)
|
||||
| (wasi_addr.addr.ip4.addr.n2 << 16)
|
||||
| (wasi_addr.addr.ip4.addr.n1 << 8)
|
||||
| wasi_addr.addr.ip4.addr.n0;
|
||||
sock_addr_in.sin_port = htons(wasi_addr.addr.ip4.port);
|
||||
memcpy(sock_addr, &sock_addr_in, sizeof(sock_addr_in));
|
||||
|
||||
*addrlen = sizeof(sock_addr_in);
|
||||
}
|
||||
else if (IPv6 == wasi_addr.kind) {
|
||||
// TODO: IPV6
|
||||
return __WASI_ERRNO_AFNOSUPPORT;
|
||||
}
|
||||
else {
|
||||
return __WASI_ERRNO_AFNOSUPPORT;
|
||||
}
|
||||
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -99,9 +143,8 @@ accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
|||
error = __wasi_sock_accept(sockfd, &new_sockfd);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
// error = sock_addr_remote(new_sockfd, addr, addrlen);
|
||||
// HANDLE_ERROR(error)
|
||||
*addrlen = 0;
|
||||
error = getpeername(new_sockfd, addr, addrlen);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
return new_sockfd;
|
||||
}
|
||||
|
@ -221,6 +264,66 @@ sendmsg(int sockfd, const struct msghdr *msg, int flags)
|
|||
return so_datalen;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||
{
|
||||
// Prepare input parameters.
|
||||
__wasi_ciovec_t iov = { .buf = buf, .buf_len = len };
|
||||
uint32_t so_datalen = 0;
|
||||
__wasi_addr_t wasi_addr;
|
||||
__wasi_errno_t error;
|
||||
size_t si_data_len = 1;
|
||||
__wasi_siflags_t si_flags = 0;
|
||||
|
||||
// This implementation does not support any flags.
|
||||
if (flags != 0) {
|
||||
HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT)
|
||||
}
|
||||
|
||||
error = sockaddr_to_wasi_addr(dest_addr, addrlen, &wasi_addr);
|
||||
HANDLE_ERROR(error);
|
||||
|
||||
// Perform system call.
|
||||
error = __wasi_sock_send_to(sockfd, &iov, si_data_len, si_flags, &wasi_addr,
|
||||
&so_datalen);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
return so_datalen;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
recvfrom(int sockfd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *src_addr, socklen_t *addrlen)
|
||||
{
|
||||
// Prepare input parameters.
|
||||
__wasi_ciovec_t iov = { .buf = buf, .buf_len = len };
|
||||
uint32_t so_datalen = 0;
|
||||
__wasi_addr_t wasi_addr;
|
||||
__wasi_errno_t error;
|
||||
size_t si_data_len = 1;
|
||||
__wasi_siflags_t si_flags = 0;
|
||||
|
||||
// This implementation does not support any flags.
|
||||
if (flags != 0) {
|
||||
HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT)
|
||||
}
|
||||
|
||||
if (!src_addr) {
|
||||
return recv(sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
// Perform system call.
|
||||
error = __wasi_sock_recv_from(sockfd, &iov, si_data_len, si_flags,
|
||||
&wasi_addr, &so_datalen);
|
||||
HANDLE_ERROR(error);
|
||||
|
||||
error = wasi_addr_to_sockaddr(&wasi_addr, src_addr, addrlen);
|
||||
HANDLE_ERROR(error);
|
||||
|
||||
return so_datalen;
|
||||
}
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol)
|
||||
{
|
||||
|
@ -256,3 +359,612 @@ socket(int domain, int type, int protocol)
|
|||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
int
|
||||
getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
__wasi_addr_t wasi_addr = { 0 };
|
||||
__wasi_errno_t error;
|
||||
|
||||
error = __wasi_sock_addr_local(sockfd, &wasi_addr);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
error = wasi_addr_to_sockaddr(&wasi_addr, addr, addrlen);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
__wasi_addr_t wasi_addr = { 0 };
|
||||
__wasi_errno_t error;
|
||||
|
||||
error = __wasi_sock_addr_remote(sockfd, &wasi_addr);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
error = wasi_addr_to_sockaddr(&wasi_addr, addr, addrlen);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
struct aibuf {
|
||||
struct addrinfo ai;
|
||||
union sa {
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
} sa;
|
||||
};
|
||||
|
||||
static __wasi_errno_t
|
||||
addrinfo_hints_to_wasi_hints(const struct addrinfo *hints,
|
||||
__wasi_addr_info_hints_t *wasi_hints)
|
||||
{
|
||||
if (hints) {
|
||||
wasi_hints->hints_enabled = 1;
|
||||
|
||||
switch (hints->ai_family) {
|
||||
case AF_INET:
|
||||
wasi_hints->family = INET4;
|
||||
break;
|
||||
case AF_INET6:
|
||||
wasi_hints->family = INET6;
|
||||
break;
|
||||
default:
|
||||
return __WASI_ERRNO_AFNOSUPPORT;
|
||||
}
|
||||
switch (hints->ai_socktype) {
|
||||
case SOCK_STREAM:
|
||||
wasi_hints->type = SOCKET_STREAM;
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
wasi_hints->type = SOCKET_DGRAM;
|
||||
break;
|
||||
default:
|
||||
return __WASI_ERRNO_NOTSUP;
|
||||
}
|
||||
|
||||
if (hints->ai_protocol != 0) {
|
||||
return __WASI_ERRNO_NOTSUP;
|
||||
}
|
||||
|
||||
if (hints->ai_flags != 0) {
|
||||
return __WASI_ERRNO_NOTSUP;
|
||||
}
|
||||
}
|
||||
else {
|
||||
wasi_hints->hints_enabled = 0;
|
||||
}
|
||||
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
static __wasi_errno_t
|
||||
wasi_addr_info_to_addr_info(const __wasi_addr_info_t *addr_info,
|
||||
struct addrinfo *ai)
|
||||
{
|
||||
ai->ai_socktype =
|
||||
addr_info->type == SOCKET_DGRAM ? SOCK_DGRAM : SOCK_STREAM;
|
||||
ai->ai_protocol = 0;
|
||||
ai->ai_canonname = NULL;
|
||||
|
||||
if (addr_info->addr.kind == IPv4) {
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
else {
|
||||
ai->ai_family = AF_INET6;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
|
||||
return wasi_addr_to_sockaddr(&addr_info->addr, ai->ai_addr,
|
||||
&ai->ai_addrlen); // TODO err handling
|
||||
}
|
||||
|
||||
int
|
||||
getaddrinfo(const char *node, const char *service, const struct addrinfo *hints,
|
||||
struct addrinfo **res)
|
||||
{
|
||||
__wasi_addr_info_hints_t wasi_hints;
|
||||
__wasi_addr_info_t *addr_info = NULL;
|
||||
__wasi_size_t addr_info_size, i;
|
||||
__wasi_size_t max_info_size = 16;
|
||||
__wasi_errno_t error;
|
||||
struct aibuf *aibuf_res;
|
||||
|
||||
error = addrinfo_hints_to_wasi_hints(hints, &wasi_hints);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
do {
|
||||
if (addr_info)
|
||||
free(addr_info);
|
||||
|
||||
addr_info_size = max_info_size;
|
||||
addr_info = (__wasi_addr_info_t *)malloc(addr_info_size
|
||||
* sizeof(__wasi_addr_info_t));
|
||||
|
||||
if (!addr_info) {
|
||||
HANDLE_ERROR(__WASI_ERRNO_NOMEM)
|
||||
}
|
||||
|
||||
error = __wasi_sock_addr_resolve(node, service == NULL ? "" : service,
|
||||
&wasi_hints, addr_info, addr_info_size,
|
||||
&max_info_size);
|
||||
if (error != __WASI_ERRNO_SUCCESS) {
|
||||
free(addr_info);
|
||||
HANDLE_ERROR(error);
|
||||
}
|
||||
} while (max_info_size > addr_info_size);
|
||||
|
||||
if (addr_info_size == 0) {
|
||||
free(addr_info);
|
||||
*res = NULL;
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
aibuf_res = calloc(1, addr_info_size * sizeof(struct aibuf));
|
||||
if (!aibuf_res) {
|
||||
free(addr_info);
|
||||
HANDLE_ERROR(__WASI_ERRNO_NOMEM)
|
||||
}
|
||||
|
||||
*res = &aibuf_res[0].ai;
|
||||
|
||||
if (addr_info_size) {
|
||||
addr_info_size = max_info_size;
|
||||
}
|
||||
|
||||
for (i = 0; i < addr_info_size; i++) {
|
||||
struct addrinfo *ai = &aibuf_res[i].ai;
|
||||
ai->ai_addr = (struct sockaddr *)&aibuf_res[i].sa;
|
||||
|
||||
error = wasi_addr_info_to_addr_info(&addr_info[i], ai);
|
||||
if (error != __WASI_ERRNO_SUCCESS) {
|
||||
free(addr_info);
|
||||
free(aibuf_res);
|
||||
HANDLE_ERROR(error)
|
||||
}
|
||||
ai->ai_next = i == addr_info_size - 1 ? NULL : &aibuf_res[i + 1].ai;
|
||||
}
|
||||
|
||||
free(addr_info);
|
||||
|
||||
return __WASI_ERRNO_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
freeaddrinfo(struct addrinfo *res)
|
||||
{
|
||||
/* res is a pointer to a first field in the first element
|
||||
* of aibuf array allocated in getaddrinfo, therefore this call
|
||||
* frees the memory of the entire array. */
|
||||
free(res);
|
||||
}
|
||||
|
||||
struct timeval
|
||||
time_us_to_timeval(uint64_t time_us)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = time_us / 1000000UL;
|
||||
tv.tv_usec = time_us % 1000000UL;
|
||||
return tv;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
timeval_to_time_us(struct timeval tv)
|
||||
{
|
||||
return (tv.tv_sec * 1000000UL) + tv.tv_usec;
|
||||
}
|
||||
|
||||
int
|
||||
get_sol_socket_option(int sockfd, int optname, void *__restrict optval,
|
||||
socklen_t *__restrict optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
uint64_t timeout_us;
|
||||
bool is_linger_enabled;
|
||||
int linger_s;
|
||||
|
||||
switch (optname) {
|
||||
case SO_RCVTIMEO:
|
||||
assert(*optlen == sizeof(struct timeval));
|
||||
error = __wasi_sock_get_recv_timeout(sockfd, &timeout_us);
|
||||
HANDLE_ERROR(error);
|
||||
*(struct timeval *)optval = time_us_to_timeval(timeout_us);
|
||||
return error;
|
||||
case SO_SNDTIMEO:
|
||||
assert(*optlen == sizeof(struct timeval));
|
||||
error = __wasi_sock_get_send_timeout(sockfd, &timeout_us);
|
||||
HANDLE_ERROR(error);
|
||||
*(struct timeval *)optval = time_us_to_timeval(timeout_us);
|
||||
return error;
|
||||
case SO_SNDBUF:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_send_buf_size(sockfd, (size_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_RCVBUF:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_recv_buf_size(sockfd, (size_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_KEEPALIVE:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_keep_alive(sockfd, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_REUSEADDR:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_reuse_addr(sockfd, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_REUSEPORT:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_reuse_port(sockfd, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_LINGER:
|
||||
assert(*optlen == sizeof(struct linger));
|
||||
error =
|
||||
__wasi_sock_get_linger(sockfd, &is_linger_enabled, &linger_s);
|
||||
HANDLE_ERROR(error);
|
||||
((struct linger *)optval)->l_onoff = (int)is_linger_enabled;
|
||||
((struct linger *)optval)->l_linger = linger_s;
|
||||
return error;
|
||||
case SO_BROADCAST:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_broadcast(sockfd, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
get_ipproto_tcp_option(int sockfd, int optname, void *__restrict optval,
|
||||
socklen_t *__restrict optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
switch (optname) {
|
||||
case TCP_KEEPIDLE:
|
||||
assert(*optlen == sizeof(uint32_t));
|
||||
error = __wasi_sock_get_tcp_keep_idle(sockfd, (uint32_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case TCP_KEEPINTVL:
|
||||
assert(*optlen == sizeof(uint32_t));
|
||||
error = __wasi_sock_get_tcp_keep_intvl(sockfd, (uint32_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case TCP_FASTOPEN_CONNECT:
|
||||
assert(*optlen == sizeof(int));
|
||||
error =
|
||||
__wasi_sock_get_tcp_fastopen_connect(sockfd, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case TCP_NODELAY:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_tcp_no_delay(sockfd, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case TCP_QUICKACK:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_tcp_quick_ack(sockfd, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
get_ipproto_ip_option(int sockfd, int optname, void *__restrict optval,
|
||||
socklen_t *__restrict optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
|
||||
switch (optname) {
|
||||
case IP_MULTICAST_LOOP:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_ip_multicast_loop(sockfd, false,
|
||||
(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IP_TTL:
|
||||
assert(*optlen == sizeof(uint8_t));
|
||||
error = __wasi_sock_get_ip_ttl(sockfd, (uint8_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IP_MULTICAST_TTL:
|
||||
assert(*optlen == sizeof(uint8_t));
|
||||
error = __wasi_sock_get_ip_multicast_ttl(sockfd, (uint8_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
get_ipproto_ipv6_option(int sockfd, int optname, void *__restrict optval,
|
||||
socklen_t *__restrict optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
|
||||
switch (optname) {
|
||||
case IPV6_V6ONLY:
|
||||
assert(*optlen == sizeof(int));
|
||||
error = __wasi_sock_get_ipv6_only(sockfd, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IPV6_MULTICAST_LOOP:
|
||||
assert(*optlen == sizeof(int));
|
||||
error =
|
||||
__wasi_sock_get_ip_multicast_loop(sockfd, true, (bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getsockopt(int sockfd, int level, int optname, void *__restrict optval,
|
||||
socklen_t *__restrict optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
|
||||
switch (level) {
|
||||
case SOL_SOCKET:
|
||||
return get_sol_socket_option(sockfd, optname, optval, optlen);
|
||||
case IPPROTO_TCP:
|
||||
return get_ipproto_tcp_option(sockfd, optname, optval, optlen);
|
||||
case IPPROTO_IP:
|
||||
return get_ipproto_ip_option(sockfd, optname, optval, optlen);
|
||||
case IPPROTO_IPV6:
|
||||
return get_ipproto_ipv6_option(sockfd, optname, optval, optlen);
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
set_sol_socket_option(int sockfd, int optname, const void *optval,
|
||||
socklen_t optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
uint64_t timeout_us;
|
||||
|
||||
switch (optname) {
|
||||
case SO_RCVTIMEO:
|
||||
assert(optlen == sizeof(struct timeval));
|
||||
timeout_us = timeval_to_time_us(*(struct timeval *)optval);
|
||||
error = __wasi_sock_set_recv_timeout(sockfd, timeout_us);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_SNDTIMEO:
|
||||
assert(optlen == sizeof(struct timeval));
|
||||
timeout_us = timeval_to_time_us(*(struct timeval *)optval);
|
||||
error = __wasi_sock_set_send_timeout(sockfd, timeout_us);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_SNDBUF:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_send_buf_size(sockfd, *(size_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_RCVBUF:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_recv_buf_size(sockfd, *(size_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_KEEPALIVE:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_keep_alive(sockfd, *(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_REUSEADDR:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_reuse_addr(sockfd, *(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_REUSEPORT:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_reuse_port(sockfd, *(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_LINGER:
|
||||
assert(optlen == sizeof(struct linger));
|
||||
struct linger *linger_opt = ((struct linger *)optval);
|
||||
error = __wasi_sock_set_linger(sockfd, (bool)linger_opt->l_onoff,
|
||||
linger_opt->l_linger);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case SO_BROADCAST:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_broadcast(sockfd, *(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
set_ipproto_tcp_option(int sockfd, int optname, const void *optval,
|
||||
socklen_t optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
|
||||
switch (optname) {
|
||||
case TCP_NODELAY:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_tcp_no_delay(sockfd, *(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case TCP_KEEPIDLE:
|
||||
assert(optlen == sizeof(uint32_t));
|
||||
error = __wasi_sock_set_tcp_keep_idle(sockfd, *(uint32_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case TCP_KEEPINTVL:
|
||||
assert(optlen == sizeof(uint32_t));
|
||||
error = __wasi_sock_set_tcp_keep_intvl(sockfd, *(uint32_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case TCP_FASTOPEN_CONNECT:
|
||||
assert(optlen == sizeof(int));
|
||||
error =
|
||||
__wasi_sock_set_tcp_fastopen_connect(sockfd, *(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case TCP_QUICKACK:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_tcp_quick_ack(sockfd, *(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
set_ipproto_ip_option(int sockfd, int optname, const void *optval,
|
||||
socklen_t optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
__wasi_addr_ip_t imr_multiaddr;
|
||||
struct ip_mreq *ip_mreq_opt;
|
||||
|
||||
switch (optname) {
|
||||
case IP_MULTICAST_LOOP:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_ip_multicast_loop(sockfd, false,
|
||||
*(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
assert(optlen == sizeof(struct ip_mreq));
|
||||
ip_mreq_opt = (struct ip_mreq *)optval;
|
||||
imr_multiaddr.kind = IPv4;
|
||||
ipv4_addr_to_wasi_ip4_addr(ip_mreq_opt->imr_multiaddr.s_addr,
|
||||
&imr_multiaddr.addr.ip4);
|
||||
error = __wasi_sock_set_ip_add_membership(
|
||||
sockfd, &imr_multiaddr, ip_mreq_opt->imr_interface.s_addr);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
assert(optlen == sizeof(struct ip_mreq));
|
||||
ip_mreq_opt = (struct ip_mreq *)optval;
|
||||
imr_multiaddr.kind = IPv4;
|
||||
ipv4_addr_to_wasi_ip4_addr(ip_mreq_opt->imr_multiaddr.s_addr,
|
||||
&imr_multiaddr.addr.ip4);
|
||||
error = __wasi_sock_set_ip_drop_membership(
|
||||
sockfd, &imr_multiaddr, ip_mreq_opt->imr_interface.s_addr);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IP_TTL:
|
||||
assert(optlen == sizeof(uint8_t));
|
||||
error = __wasi_sock_set_ip_ttl(sockfd, *(uint8_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IP_MULTICAST_TTL:
|
||||
assert(optlen == sizeof(uint8_t));
|
||||
error =
|
||||
__wasi_sock_set_ip_multicast_ttl(sockfd, *(uint8_t *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
set_ipproto_ipv6_option(int sockfd, int optname, const void *optval,
|
||||
socklen_t optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
struct ipv6_mreq *ipv6_mreq_opt;
|
||||
__wasi_addr_ip_t imr_multiaddr;
|
||||
|
||||
switch (optname) {
|
||||
case IPV6_V6ONLY:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_ipv6_only(sockfd, *(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IPV6_MULTICAST_LOOP:
|
||||
assert(optlen == sizeof(int));
|
||||
error = __wasi_sock_set_ip_multicast_loop(sockfd, true,
|
||||
*(bool *)optval);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IPV6_JOIN_GROUP:
|
||||
assert(optlen == sizeof(struct ipv6_mreq));
|
||||
ipv6_mreq_opt = (struct ipv6_mreq *)optval;
|
||||
imr_multiaddr.kind = IPv6;
|
||||
ipv6_addr_to_wasi_ipv6_addr(
|
||||
(uint16_t *)ipv6_mreq_opt->ipv6mr_multiaddr.s6_addr,
|
||||
&imr_multiaddr.addr.ip6);
|
||||
error = __wasi_sock_set_ip_add_membership(
|
||||
sockfd, &imr_multiaddr, ipv6_mreq_opt->ipv6mr_interface);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
case IPV6_LEAVE_GROUP:
|
||||
assert(optlen == sizeof(struct ipv6_mreq));
|
||||
ipv6_mreq_opt = (struct ipv6_mreq *)optval;
|
||||
imr_multiaddr.kind = IPv6;
|
||||
ipv6_addr_to_wasi_ipv6_addr(
|
||||
(uint16_t *)ipv6_mreq_opt->ipv6mr_multiaddr.s6_addr,
|
||||
&imr_multiaddr.addr.ip6);
|
||||
error = __wasi_sock_set_ip_drop_membership(
|
||||
sockfd, &imr_multiaddr, ipv6_mreq_opt->ipv6mr_interface);
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
setsockopt(int sockfd, int level, int optname, const void *optval,
|
||||
socklen_t optlen)
|
||||
{
|
||||
__wasi_errno_t error;
|
||||
|
||||
switch (level) {
|
||||
case SOL_SOCKET:
|
||||
return set_sol_socket_option(sockfd, optname, optval, optlen);
|
||||
case IPPROTO_TCP:
|
||||
return set_ipproto_tcp_option(sockfd, optname, optval, optlen);
|
||||
case IPPROTO_IP:
|
||||
return set_ipproto_ip_option(sockfd, optname, optval, optlen);
|
||||
case IPPROTO_IPV6:
|
||||
return set_ipproto_ipv6_option(sockfd, optname, optval, optlen);
|
||||
default:
|
||||
error = __WASI_ERRNO_NOTSUP;
|
||||
HANDLE_ERROR(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,6 +18,7 @@
|
|||
#ifndef WASMTIME_SSP_H
|
||||
#define WASMTIME_SSP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -588,6 +589,14 @@ typedef struct __wasi_addr_ip6_port_t {
|
|||
__wasi_ip_port_t port;
|
||||
} __wasi_addr_ip6_port_t;
|
||||
|
||||
typedef struct __wasi_addr_ip_t {
|
||||
__wasi_addr_type_t kind;
|
||||
union {
|
||||
__wasi_addr_ip4_t ip4;
|
||||
__wasi_addr_ip6_t ip6;
|
||||
} addr;
|
||||
} __wasi_addr_ip_t;
|
||||
|
||||
typedef struct __wasi_addr_t {
|
||||
__wasi_addr_type_t kind;
|
||||
union {
|
||||
|
@ -598,6 +607,18 @@ typedef struct __wasi_addr_t {
|
|||
|
||||
typedef enum { INET4 = 0, INET6 } __wasi_address_family_t;
|
||||
|
||||
typedef struct __wasi_addr_info_t {
|
||||
__wasi_addr_t addr;
|
||||
__wasi_sock_type_t type;
|
||||
} __wasi_addr_info_t;
|
||||
|
||||
typedef struct __wasi_addr_info_hints_t {
|
||||
__wasi_sock_type_t type;
|
||||
__wasi_address_family_t family;
|
||||
// this is to workaround lack of optional parameters
|
||||
uint8_t hints_enabled;
|
||||
} __wasi_addr_info_hints_t;
|
||||
|
||||
#if defined(WASMTIME_SSP_WASI_API)
|
||||
#define WASMTIME_SSP_SYSCALL_NAME(name) \
|
||||
asm("__wasi_" #name)
|
||||
|
@ -995,7 +1016,7 @@ wasi_ssp_sock_addr_local(
|
|||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len
|
||||
__wasi_fd_t fd, __wasi_addr_t *addr
|
||||
) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t
|
||||
|
@ -1003,7 +1024,7 @@ wasi_ssp_sock_addr_remote(
|
|||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len
|
||||
__wasi_fd_t fd, __wasi_addr_t *addr
|
||||
) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t
|
||||
|
@ -1023,6 +1044,16 @@ wasi_ssp_sock_bind(
|
|||
__wasi_fd_t fd, __wasi_addr_t *addr
|
||||
) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t
|
||||
wasi_ssp_sock_addr_resolve(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds, char **ns_lookup_list,
|
||||
#endif
|
||||
const char *host, const char* service,
|
||||
__wasi_addr_info_hints_t *hints, __wasi_addr_info_t *addr_info,
|
||||
__wasi_size_t addr_info_size, __wasi_size_t *max_info_size
|
||||
) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t
|
||||
wasi_ssp_sock_connect(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
|
@ -1049,6 +1080,18 @@ __wasi_errno_t wasmtime_ssp_sock_recv(
|
|||
size_t *recv_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_recv_from(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
void *buf,
|
||||
size_t buf_len,
|
||||
__wasi_riflags_t ri_flags,
|
||||
__wasi_addr_t *src_addr,
|
||||
size_t *recv_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_recv_from) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_send(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
|
@ -1059,6 +1102,18 @@ __wasi_errno_t wasmtime_ssp_sock_send(
|
|||
size_t *sent_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_send_to(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds, struct addr_pool *addr_pool,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
const void *buf,
|
||||
size_t buf_len,
|
||||
__wasi_siflags_t si_flags,
|
||||
const __wasi_addr_t *dest_addr,
|
||||
size_t *sent_len
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_send_to) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_shutdown(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
|
@ -1066,6 +1121,315 @@ __wasi_errno_t wasmtime_ssp_sock_shutdown(
|
|||
__wasi_fd_t sock
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_recv_timeout(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint64_t timeout_us
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_timeout) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_recv_timeout(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint64_t *timeout_us
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_timeout) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_send_timeout(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint64_t timeout_us
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_timeout) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_send_timeout(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint64_t *timeout_us
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_send_buf_size(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
size_t bufsiz
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_buf_size) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_send_buf_size(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
size_t *bufsiz
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_buf_size) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_recv_buf_size(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
size_t bufsiz
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_buf_size) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_recv_buf_size(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
size_t *bufsiz
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_buf_size) __attribute__((__warn_unused_result__));
|
||||
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_keep_alive(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_keep_alive) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_keep_alive(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_reuse_addr(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_addr) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_reuse_addr(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_reuse_port(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_port) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_reuse_port(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_linger(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled,
|
||||
int linger_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_linger(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, bool *is_enabled, int *linger_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_linger) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_broadcast(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_broadcast) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_broadcast(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_tcp_no_delay(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_no_delay) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_tcp_no_delay(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_tcp_quick_ack(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_quick_ack) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_tcp_quick_ack(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_idle(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint32_t time_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_idle) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_idle(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint32_t *time_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_idle) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_intvl(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint32_t time_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_intvl) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_intvl(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint32_t *time_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_intvl) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_tcp_fastopen_connect(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_fastopen_connect) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_tcp_fastopen_connect(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_loop(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool ipv6,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_loop) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_loop(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool ipv6,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_ip_add_membership(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
__wasi_addr_ip_t *imr_multiaddr,
|
||||
uint32_t imr_interface
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_add_membership) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_ip_drop_membership(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
__wasi_addr_ip_t *imr_multiaddr,
|
||||
uint32_t imr_interface
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_drop_membership) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_ip_ttl(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint8_t ttl_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_ttl) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_ip_ttl(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint8_t *ttl_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_ttl) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_ttl(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint8_t ttl_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_ttl) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_ttl(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
uint8_t *ttl_s
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_ttl) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_set_ipv6_only(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_set_ipv6_only) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sock_get_ipv6_only(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock,
|
||||
bool *is_enabled
|
||||
) WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) __attribute__((__warn_unused_result__));
|
||||
|
||||
__wasi_errno_t wasmtime_ssp_sched_yield(void)
|
||||
WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__));
|
||||
|
||||
|
|
|
@ -161,6 +161,31 @@ convert_errno(int error)
|
|||
return errors[error];
|
||||
}
|
||||
|
||||
static bool
|
||||
ns_lookup_list_search(char **list, const char *host)
|
||||
{
|
||||
size_t host_len = strlen(host), suffix_len;
|
||||
|
||||
while (*list) {
|
||||
if (*list[0] == '*') {
|
||||
suffix_len = strlen(*list) - 1;
|
||||
if (suffix_len <= host_len
|
||||
&& strncmp(host + host_len - suffix_len, *list + 1, suffix_len)
|
||||
== 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (strcmp(*list, host) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
list++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Converts a POSIX timespec to a CloudABI timestamp.
|
||||
static __wasi_timestamp_t
|
||||
convert_timespec(const struct timespec *ts)
|
||||
|
@ -199,6 +224,82 @@ convert_clockid(__wasi_clockid_t in, clockid_t *out)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wasi_addr_to_bh_sockaddr(const __wasi_addr_t *wasi_addr,
|
||||
bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
if (wasi_addr->kind == IPv4) {
|
||||
sockaddr->addr_bufer.ipv4 = (wasi_addr->addr.ip4.addr.n0 << 24)
|
||||
| (wasi_addr->addr.ip4.addr.n1 << 16)
|
||||
| (wasi_addr->addr.ip4.addr.n2 << 8)
|
||||
| wasi_addr->addr.ip4.addr.n3;
|
||||
sockaddr->is_ipv4 = true;
|
||||
sockaddr->port = wasi_addr->addr.ip4.port;
|
||||
}
|
||||
else {
|
||||
sockaddr->addr_bufer.ipv6[0] = wasi_addr->addr.ip6.addr.n0;
|
||||
sockaddr->addr_bufer.ipv6[1] = wasi_addr->addr.ip6.addr.n1;
|
||||
sockaddr->addr_bufer.ipv6[2] = wasi_addr->addr.ip6.addr.n2;
|
||||
sockaddr->addr_bufer.ipv6[3] = wasi_addr->addr.ip6.addr.n3;
|
||||
sockaddr->addr_bufer.ipv6[4] = wasi_addr->addr.ip6.addr.h0;
|
||||
sockaddr->addr_bufer.ipv6[5] = wasi_addr->addr.ip6.addr.h1;
|
||||
sockaddr->addr_bufer.ipv6[6] = wasi_addr->addr.ip6.addr.h2;
|
||||
sockaddr->addr_bufer.ipv6[7] = wasi_addr->addr.ip6.addr.h3;
|
||||
sockaddr->is_ipv4 = false;
|
||||
sockaddr->port = wasi_addr->addr.ip6.port;
|
||||
}
|
||||
}
|
||||
|
||||
// Converts an IPv6 binary address object to WASI address object.
|
||||
static void
|
||||
bh_sockaddr_to_wasi_addr(const bh_sockaddr_t *sockaddr,
|
||||
__wasi_addr_t *wasi_addr)
|
||||
{
|
||||
if (sockaddr->is_ipv4) {
|
||||
wasi_addr->kind = IPv4;
|
||||
wasi_addr->addr.ip4.port = sockaddr->port;
|
||||
wasi_addr->addr.ip4.addr.n0 =
|
||||
(sockaddr->addr_bufer.ipv4 & 0xFF000000) >> 24;
|
||||
wasi_addr->addr.ip4.addr.n1 =
|
||||
(sockaddr->addr_bufer.ipv4 & 0x00FF0000) >> 16;
|
||||
wasi_addr->addr.ip4.addr.n2 =
|
||||
(sockaddr->addr_bufer.ipv4 & 0x0000FF00) >> 8;
|
||||
wasi_addr->addr.ip4.addr.n3 = (sockaddr->addr_bufer.ipv4 & 0x000000FF);
|
||||
}
|
||||
else {
|
||||
wasi_addr->kind = IPv6;
|
||||
wasi_addr->addr.ip6.port = sockaddr->port;
|
||||
wasi_addr->addr.ip6.addr.n0 = sockaddr->addr_bufer.ipv6[0];
|
||||
wasi_addr->addr.ip6.addr.n1 = sockaddr->addr_bufer.ipv6[1];
|
||||
wasi_addr->addr.ip6.addr.n2 = sockaddr->addr_bufer.ipv6[2];
|
||||
wasi_addr->addr.ip6.addr.n3 = sockaddr->addr_bufer.ipv6[3];
|
||||
wasi_addr->addr.ip6.addr.h0 = sockaddr->addr_bufer.ipv6[4];
|
||||
wasi_addr->addr.ip6.addr.h1 = sockaddr->addr_bufer.ipv6[5];
|
||||
wasi_addr->addr.ip6.addr.h2 = sockaddr->addr_bufer.ipv6[6];
|
||||
wasi_addr->addr.ip6.addr.h3 = sockaddr->addr_bufer.ipv6[7];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wasi_addr_ip_to_bh_ip_addr_buffer(__wasi_addr_ip_t *addr,
|
||||
bh_ip_addr_buffer_t *out)
|
||||
{
|
||||
if (addr->kind == IPv4) {
|
||||
out->ipv4 = htonl((addr->addr.ip4.n0 << 24) | (addr->addr.ip4.n1 << 16)
|
||||
| (addr->addr.ip4.n2 << 8) | addr->addr.ip4.n3);
|
||||
}
|
||||
else {
|
||||
out->ipv6[0] = htons(addr->addr.ip6.n0);
|
||||
out->ipv6[1] = htons(addr->addr.ip6.n1);
|
||||
out->ipv6[2] = htons(addr->addr.ip6.n2);
|
||||
out->ipv6[3] = htons(addr->addr.ip6.n3);
|
||||
out->ipv6[4] = htons(addr->addr.ip6.h0);
|
||||
out->ipv6[5] = htons(addr->addr.ip6.h1);
|
||||
out->ipv6[6] = htons(addr->addr.ip6.h2);
|
||||
out->ipv6[7] = htons(addr->addr.ip6.h3);
|
||||
}
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id,
|
||||
__wasi_timestamp_t *resolution)
|
||||
|
@ -2852,16 +2953,26 @@ wasi_ssp_sock_addr_local(
|
|||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len)
|
||||
__wasi_fd_t fd, __wasi_addr_t *addr)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
bh_sockaddr_t bh_addr;
|
||||
int ret;
|
||||
|
||||
__wasi_errno_t error =
|
||||
fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0);
|
||||
if (error != __WASI_ESUCCESS)
|
||||
return error;
|
||||
|
||||
ret = os_socket_addr_local(fd_number(fo), &bh_addr);
|
||||
fd_object_release(fo);
|
||||
return __WASI_ENOSYS;
|
||||
if (ret != BHT_OK) {
|
||||
return convert_errno(errno);
|
||||
}
|
||||
|
||||
bh_sockaddr_to_wasi_addr(&bh_addr, addr);
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
|
@ -2869,16 +2980,55 @@ wasi_ssp_sock_addr_remote(
|
|||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len)
|
||||
__wasi_fd_t fd, __wasi_addr_t *addr)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
bh_sockaddr_t bh_addr;
|
||||
int ret;
|
||||
|
||||
__wasi_errno_t error =
|
||||
fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_REMOTE, 0);
|
||||
fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0);
|
||||
if (error != __WASI_ESUCCESS)
|
||||
return error;
|
||||
|
||||
ret = os_socket_addr_remote(fd_number(fo), &bh_addr);
|
||||
fd_object_release(fo);
|
||||
return __WASI_ENOSYS;
|
||||
if (ret != BHT_OK) {
|
||||
return convert_errno(errno);
|
||||
}
|
||||
|
||||
bh_sockaddr_to_wasi_addr(&bh_addr, addr);
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
static bool
|
||||
wasi_addr_to_string(const __wasi_addr_t *addr, char *buf, size_t buflen)
|
||||
{
|
||||
if (addr->kind == IPv4) {
|
||||
const char *format = "%u.%u.%u.%u";
|
||||
|
||||
assert(buflen >= 16);
|
||||
|
||||
snprintf(buf, buflen, format, addr->addr.ip4.addr.n0,
|
||||
addr->addr.ip4.addr.n1, addr->addr.ip4.addr.n2,
|
||||
addr->addr.ip4.addr.n3);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (addr->kind == IPv6) {
|
||||
const char *format = "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x";
|
||||
__wasi_addr_ip6_t ipv6 = addr->addr.ip6.addr;
|
||||
|
||||
assert(buflen >= 40);
|
||||
|
||||
snprintf(buf, buflen, format, ipv6.n0, ipv6.n1, ipv6.n2, ipv6.n3,
|
||||
ipv6.h0, ipv6.h1, ipv6.h2, ipv6.h3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
|
@ -2888,15 +3038,15 @@ wasi_ssp_sock_bind(
|
|||
#endif
|
||||
__wasi_fd_t fd, __wasi_addr_t *addr)
|
||||
{
|
||||
char buf[24] = { 0 };
|
||||
const char *format = "%u.%u.%u.%u";
|
||||
char buf[48] = { 0 };
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int port = addr->addr.ip4.port;
|
||||
int port = addr->kind == IPv4 ? addr->addr.ip4.port : addr->addr.ip6.port;
|
||||
int ret;
|
||||
|
||||
snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1,
|
||||
addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3);
|
||||
if (!wasi_addr_to_string(addr, buf, sizeof(buf))) {
|
||||
return __WASI_EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
if (!addr_pool_search(addr_pool, buf)) {
|
||||
return __WASI_EACCES;
|
||||
|
@ -2915,6 +3065,55 @@ wasi_ssp_sock_bind(
|
|||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasi_ssp_sock_addr_resolve(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds, char **ns_lookup_list,
|
||||
#endif
|
||||
const char *host, const char *service, __wasi_addr_info_hints_t *hints,
|
||||
__wasi_addr_info_t *addr_info, __wasi_size_t addr_info_size,
|
||||
__wasi_size_t *max_info_size)
|
||||
{
|
||||
bh_addr_info_t *wamr_addr_info =
|
||||
wasm_runtime_malloc(addr_info_size * sizeof(bh_addr_info_t));
|
||||
uint8_t hints_is_ipv4 = hints->family == INET4;
|
||||
uint8_t hints_is_tcp = hints->type == SOCKET_STREAM;
|
||||
size_t _max_info_size;
|
||||
size_t actual_info_size;
|
||||
|
||||
if (!ns_lookup_list_search(ns_lookup_list, host)) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
|
||||
if (!wamr_addr_info) {
|
||||
return __WASI_ENOMEM;
|
||||
}
|
||||
|
||||
int ret = os_socket_addr_resolve(
|
||||
host, service, hints->hints_enabled ? &hints_is_tcp : NULL,
|
||||
hints->hints_enabled ? &hints_is_ipv4 : NULL, wamr_addr_info,
|
||||
addr_info_size, &_max_info_size);
|
||||
|
||||
if (ret != BHT_OK) {
|
||||
wasm_runtime_free(wamr_addr_info);
|
||||
return convert_errno(errno);
|
||||
}
|
||||
|
||||
*max_info_size = _max_info_size;
|
||||
actual_info_size =
|
||||
addr_info_size < *max_info_size ? addr_info_size : *max_info_size;
|
||||
|
||||
for (size_t i = 0; i < actual_info_size; i++) {
|
||||
addr_info[i].type =
|
||||
wamr_addr_info[i].is_tcp ? SOCKET_STREAM : SOCKET_DGRAM;
|
||||
bh_sockaddr_to_wasi_addr(&wamr_addr_info[i].sockaddr,
|
||||
&addr_info[i].addr);
|
||||
}
|
||||
|
||||
wasm_runtime_free(wamr_addr_info);
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasi_ssp_sock_connect(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
|
@ -2922,14 +3121,14 @@ wasi_ssp_sock_connect(
|
|||
#endif
|
||||
__wasi_fd_t fd, __wasi_addr_t *addr)
|
||||
{
|
||||
char buf[24] = { 0 };
|
||||
const char *format = "%u.%u.%u.%u";
|
||||
char buf[48] = { 0 };
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int ret;
|
||||
|
||||
snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1,
|
||||
addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3);
|
||||
if (!wasi_addr_to_string(addr, buf, sizeof(buf))) {
|
||||
return __WASI_EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
if (!addr_pool_search(addr_pool, buf)) {
|
||||
return __WASI_EACCES;
|
||||
|
@ -2939,7 +3138,9 @@ wasi_ssp_sock_connect(
|
|||
if (error != __WASI_ESUCCESS)
|
||||
return error;
|
||||
|
||||
ret = os_socket_connect(fd_number(fo), buf, addr->addr.ip4.port);
|
||||
ret = os_socket_connect(fd_number(fo), buf,
|
||||
addr->kind == IPv4 ? addr->addr.ip4.port
|
||||
: addr->addr.ip6.port);
|
||||
fd_object_release(fo);
|
||||
if (BHT_OK != ret) {
|
||||
return convert_errno(errno);
|
||||
|
@ -2980,7 +3181,8 @@ wasi_ssp_sock_open(
|
|||
__wasi_fd_t *sockfd)
|
||||
{
|
||||
bh_socket_t sock;
|
||||
int tcp_or_udp = 0;
|
||||
bool is_tcp = SOCKET_DGRAM == socktype ? false : true;
|
||||
bool is_ipv4 = INET6 == af ? false : true;
|
||||
int ret;
|
||||
__wasi_filetype_t wasi_type;
|
||||
__wasi_rights_t max_base, max_inheriting;
|
||||
|
@ -2988,13 +3190,7 @@ wasi_ssp_sock_open(
|
|||
|
||||
(void)poolfd;
|
||||
|
||||
if (INET4 != af) {
|
||||
return __WASI_EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
tcp_or_udp = SOCKET_DGRAM == socktype ? 0 : 1;
|
||||
|
||||
ret = os_socket_create(&sock, tcp_or_udp);
|
||||
ret = os_socket_create(&sock, is_ipv4, is_tcp);
|
||||
if (BHT_OK != ret) {
|
||||
return convert_errno(errno);
|
||||
}
|
||||
|
@ -3029,9 +3225,24 @@ wasmtime_ssp_sock_recv(
|
|||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, void *buf, size_t buf_len, size_t *recv_len)
|
||||
{
|
||||
__wasi_addr_t src_addr;
|
||||
|
||||
return wasmtime_ssp_sock_recv_from(curfds, sock, buf, buf_len, 0, &src_addr,
|
||||
recv_len);
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_recv_from(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, void *buf, size_t buf_len, __wasi_riflags_t ri_flags,
|
||||
__wasi_addr_t *src_addr, size_t *recv_len)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
bh_sockaddr_t sockaddr;
|
||||
int ret;
|
||||
|
||||
error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0);
|
||||
|
@ -3039,12 +3250,14 @@ wasmtime_ssp_sock_recv(
|
|||
return error;
|
||||
}
|
||||
|
||||
ret = os_socket_recv(fd_number(fo), buf, buf_len);
|
||||
ret = os_socket_recv_from(fd_number(fo), buf, buf_len, 0, &sockaddr);
|
||||
fd_object_release(fo);
|
||||
if (-1 == ret) {
|
||||
return convert_errno(errno);
|
||||
}
|
||||
|
||||
bh_sockaddr_to_wasi_addr(&sockaddr, src_addr);
|
||||
|
||||
*recv_len = (size_t)ret;
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
@ -3075,6 +3288,45 @@ wasmtime_ssp_sock_send(
|
|||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_send_to(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds, struct addr_pool *addr_pool,
|
||||
#endif
|
||||
__wasi_fd_t sock, const void *buf, size_t buf_len,
|
||||
__wasi_siflags_t si_flags, const __wasi_addr_t *dest_addr, size_t *sent_len)
|
||||
{
|
||||
char addr_buf[48] = { 0 };
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int ret;
|
||||
bh_sockaddr_t sockaddr;
|
||||
|
||||
if (!wasi_addr_to_string(dest_addr, addr_buf, sizeof(addr_buf))) {
|
||||
return __WASI_EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
if (!addr_pool_search(addr_pool, addr_buf)) {
|
||||
return __WASI_EACCES;
|
||||
}
|
||||
|
||||
error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0);
|
||||
if (error != 0) {
|
||||
return error;
|
||||
}
|
||||
|
||||
wasi_addr_to_bh_sockaddr(dest_addr, &sockaddr);
|
||||
|
||||
ret = os_socket_send_to(fd_number(fo), buf, buf_len, 0, &sockaddr);
|
||||
fd_object_release(fo);
|
||||
if (-1 == ret) {
|
||||
return convert_errno(errno);
|
||||
}
|
||||
|
||||
*sent_len = (size_t)ret;
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_shutdown(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
|
@ -3220,9 +3472,8 @@ fd_prestats_destroy(struct fd_prestats *pt)
|
|||
bool
|
||||
addr_pool_init(struct addr_pool *addr_pool)
|
||||
{
|
||||
addr_pool->next = NULL;
|
||||
addr_pool->addr = 0;
|
||||
addr_pool->mask = 0;
|
||||
memset(addr_pool, 0, sizeof(*addr_pool));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3231,6 +3482,7 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
|
|||
{
|
||||
struct addr_pool *cur = addr_pool;
|
||||
struct addr_pool *next;
|
||||
bh_ip_addr_buffer_t target;
|
||||
|
||||
if (!addr_pool) {
|
||||
return false;
|
||||
|
@ -3242,9 +3494,20 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
|
|||
|
||||
next->next = NULL;
|
||||
next->mask = mask;
|
||||
if (os_socket_inet_network(addr, &next->addr) != BHT_OK) {
|
||||
wasm_runtime_free(next);
|
||||
return false;
|
||||
|
||||
if (os_socket_inet_network(true, addr, &target) != BHT_OK) {
|
||||
// If parsing IPv4 fails, try IPv6
|
||||
if (os_socket_inet_network(false, addr, &target) != BHT_OK) {
|
||||
wasm_runtime_free(next);
|
||||
return false;
|
||||
}
|
||||
next->type = IPv6;
|
||||
bh_memcpy_s(next->addr.ip6, sizeof(next->addr.ip6), target.ipv6,
|
||||
sizeof(target.ipv6));
|
||||
}
|
||||
else {
|
||||
next->type = IPv4;
|
||||
next->addr.ip4 = target.ipv4;
|
||||
}
|
||||
|
||||
/* attach with */
|
||||
|
@ -3255,47 +3518,106 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
compare_address(const struct addr_pool *addr_pool_entry, const char *addr)
|
||||
static inline size_t
|
||||
min(size_t a, size_t b)
|
||||
{
|
||||
/* host order */
|
||||
uint32 target;
|
||||
uint32 address = addr_pool_entry->addr;
|
||||
/* 0.0.0.0 means any address */
|
||||
if (0 == address) {
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
static void
|
||||
init_address_mask(uint8_t *buf, size_t buflen, size_t mask)
|
||||
{
|
||||
size_t element_size = sizeof(uint8_t) * 8;
|
||||
|
||||
for (size_t i = 0; i < buflen; i++) {
|
||||
if (mask <= i * element_size) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
else {
|
||||
size_t offset = min(mask - i * element_size, element_size);
|
||||
buf[i] = (~0u) << (element_size - offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* target must be in network byte order */
|
||||
static bool
|
||||
compare_address(const struct addr_pool *addr_pool_entry,
|
||||
bh_ip_addr_buffer_t *target)
|
||||
{
|
||||
uint8_t maskbuf[16] = { 0 };
|
||||
uint8_t basebuf[16] = { 0 };
|
||||
size_t addr_size;
|
||||
uint8_t max_addr_mask;
|
||||
|
||||
if (addr_pool_entry->type == IPv4) {
|
||||
uint32_t addr_ip4 = htonl(addr_pool_entry->addr.ip4);
|
||||
bh_memcpy_s(basebuf, sizeof(addr_ip4), &addr_ip4, sizeof(addr_ip4));
|
||||
addr_size = 4;
|
||||
}
|
||||
else {
|
||||
uint16_t partial_addr_ip6;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
partial_addr_ip6 = htons(addr_pool_entry->addr.ip6[i]);
|
||||
bh_memcpy_s(&basebuf[i * sizeof(partial_addr_ip6)],
|
||||
sizeof(partial_addr_ip6), &partial_addr_ip6,
|
||||
sizeof(partial_addr_ip6));
|
||||
}
|
||||
addr_size = 16;
|
||||
}
|
||||
max_addr_mask = addr_size * 8;
|
||||
|
||||
/* IPv4 0.0.0.0 or IPv6 :: means any address */
|
||||
if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (os_socket_inet_network(addr, &target) != BHT_OK) {
|
||||
/* No support for invalid mask value */
|
||||
if (addr_pool_entry->mask > max_addr_mask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32 max_mask_value = 32;
|
||||
/* no support for invalid mask values */
|
||||
if (addr_pool_entry->mask > max_mask_value) {
|
||||
return false;
|
||||
init_address_mask(maskbuf, addr_size, addr_pool_entry->mask);
|
||||
|
||||
for (size_t i = 0; i < addr_size; i++) {
|
||||
uint8_t addr_mask = target->data[i] & maskbuf[i];
|
||||
uint8_t range_mask = basebuf[i] & maskbuf[i];
|
||||
if (addr_mask != range_mask) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert mask number into 32-bit mask value, i.e. mask /24 will be
|
||||
converted to 4294967040 (binary: 11111111 11111111 11111111 00000000) */
|
||||
uint32 mask = 0;
|
||||
for (int i = 0; i < addr_pool_entry->mask; i++) {
|
||||
mask |= 1 << (max_mask_value - 1 - i);
|
||||
}
|
||||
|
||||
uint32 first_address = address & mask;
|
||||
uint32 last_address = address | (~mask);
|
||||
return first_address <= target && target <= last_address;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
addr_pool_search(struct addr_pool *addr_pool, const char *addr)
|
||||
{
|
||||
struct addr_pool *cur = addr_pool->next;
|
||||
bh_ip_addr_buffer_t target;
|
||||
__wasi_addr_type_t addr_type;
|
||||
|
||||
if (os_socket_inet_network(true, addr, &target) != BHT_OK) {
|
||||
size_t i;
|
||||
|
||||
if (os_socket_inet_network(false, addr, &target) != BHT_OK) {
|
||||
return false;
|
||||
}
|
||||
addr_type = IPv6;
|
||||
for (i = 0; i < sizeof(target.ipv6) / sizeof(target.ipv6[0]); i++) {
|
||||
target.ipv6[i] = htons(target.ipv6[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
addr_type = IPv4;
|
||||
target.ipv4 = htonl(target.ipv4);
|
||||
}
|
||||
|
||||
while (cur) {
|
||||
if (compare_address(cur, addr))
|
||||
if (cur->type == addr_type && compare_address(cur, &target)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
|
@ -3313,3 +3635,203 @@ addr_pool_destroy(struct addr_pool *addr_pool)
|
|||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WASMTIME_SSP_STATIC_CURFDS
|
||||
#define WASMTIME_SSP_PASSTHROUGH_FD_TABLE struct fd_table *curfds,
|
||||
#else
|
||||
#define WASMTIME_SSP_PASSTHROUGH_FD_TABLE
|
||||
#endif
|
||||
|
||||
// Defines a function that passes through the socket option to the OS
|
||||
// implementation
|
||||
#define WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(FUNC_NAME, OPTION_TYPE) \
|
||||
__wasi_errno_t wasmtime_ssp_sock_##FUNC_NAME( \
|
||||
WASMTIME_SSP_PASSTHROUGH_FD_TABLE __wasi_fd_t sock, \
|
||||
OPTION_TYPE option) \
|
||||
{ \
|
||||
struct fd_object *fo; \
|
||||
__wasi_errno_t error; \
|
||||
int ret; \
|
||||
error = fd_object_get(curfds, &fo, sock, 0, 0); \
|
||||
if (error != 0) \
|
||||
return error; \
|
||||
ret = os_socket_##FUNC_NAME(fd_number(fo), option); \
|
||||
fd_object_release(fo); \
|
||||
if (BHT_OK != ret) \
|
||||
return convert_errno(errno); \
|
||||
return __WASI_ESUCCESS; \
|
||||
}
|
||||
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_timeout, uint64)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_timeout, uint64 *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_timeout, uint64)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_timeout, uint64 *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_buf_size, size_t)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_buf_size, size_t *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_buf_size, size_t)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_buf_size, size_t *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_broadcast, bool)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_broadcast, bool *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_keep_alive, bool)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_keep_alive, bool *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_reuse_addr, bool)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_reuse_addr, bool *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_reuse_port, bool)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_reuse_port, bool *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_no_delay, bool)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_no_delay, bool *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_quick_ack, bool)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_quick_ack, bool *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_keep_idle, uint32)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_keep_idle, uint32 *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_keep_intvl, uint32)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_keep_intvl, uint32 *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_fastopen_connect, bool)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_fastopen_connect, bool *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ip_ttl, uint8_t)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ip_ttl, uint8_t *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ip_multicast_ttl, uint8_t)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ip_multicast_ttl, uint8_t *)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ipv6_only, bool)
|
||||
WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ipv6_only, bool *)
|
||||
|
||||
#undef WASMTIME_SSP_PASSTHROUGH_FD_TABLE
|
||||
#undef WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_set_linger(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, bool is_enabled, int linger_s)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int ret;
|
||||
error = fd_object_get(curfds, &fo, sock, 0, 0);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
ret = os_socket_set_linger(fd_number(fo), is_enabled, linger_s);
|
||||
fd_object_release(fo);
|
||||
if (BHT_OK != ret)
|
||||
return convert_errno(errno);
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_get_linger(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, bool *is_enabled, int *linger_s)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int ret;
|
||||
error = fd_object_get(curfds, &fo, sock, 0, 0);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
ret = os_socket_get_linger(fd_number(fo), is_enabled, linger_s);
|
||||
fd_object_release(fo);
|
||||
if (BHT_OK != ret)
|
||||
return convert_errno(errno);
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_set_ip_add_membership(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, __wasi_addr_ip_t *imr_multiaddr, uint32_t imr_interface)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int ret;
|
||||
bh_ip_addr_buffer_t addr_info;
|
||||
bool is_ipv6;
|
||||
error = fd_object_get(curfds, &fo, sock, 0, 0);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info);
|
||||
is_ipv6 = imr_multiaddr->kind == IPv6;
|
||||
ret = os_socket_set_ip_add_membership(fd_number(fo), &addr_info,
|
||||
imr_interface, is_ipv6);
|
||||
fd_object_release(fo);
|
||||
if (BHT_OK != ret)
|
||||
return convert_errno(errno);
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_set_ip_drop_membership(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, __wasi_addr_ip_t *imr_multiaddr, uint32_t imr_interface)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int ret;
|
||||
bh_ip_addr_buffer_t addr_info;
|
||||
bool is_ipv6;
|
||||
error = fd_object_get(curfds, &fo, sock, 0, 0);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info);
|
||||
is_ipv6 = imr_multiaddr->kind == IPv6;
|
||||
ret = os_socket_set_ip_drop_membership(fd_number(fo), &addr_info,
|
||||
imr_interface, is_ipv6);
|
||||
fd_object_release(fo);
|
||||
if (BHT_OK != ret)
|
||||
return convert_errno(errno);
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_set_ip_multicast_loop(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, bool ipv6, bool is_enabled)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int ret;
|
||||
error = fd_object_get(curfds, &fo, sock, 0, 0);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
ret = os_socket_set_ip_multicast_loop(fd_number(fo), ipv6, is_enabled);
|
||||
fd_object_release(fo);
|
||||
if (BHT_OK != ret)
|
||||
return convert_errno(errno);
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
wasmtime_ssp_sock_get_ip_multicast_loop(
|
||||
#if !defined(WASMTIME_SSP_STATIC_CURFDS)
|
||||
struct fd_table *curfds,
|
||||
#endif
|
||||
__wasi_fd_t sock, bool ipv6, bool *is_enabled)
|
||||
{
|
||||
struct fd_object *fo;
|
||||
__wasi_errno_t error;
|
||||
int ret;
|
||||
error = fd_object_get(curfds, &fo, sock, 0, 0);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
ret = os_socket_get_ip_multicast_loop(fd_number(fo), ipv6, is_enabled);
|
||||
fd_object_release(fo);
|
||||
if (BHT_OK != ret)
|
||||
return convert_errno(errno);
|
||||
|
||||
return __WASI_ESUCCESS;
|
||||
}
|
||||
|
|
|
@ -47,9 +47,13 @@ struct argv_environ_values {
|
|||
};
|
||||
|
||||
struct addr_pool {
|
||||
struct addr_pool *next;
|
||||
/* addr and mask in host order */
|
||||
uint32 addr;
|
||||
union {
|
||||
uint32 ip4;
|
||||
uint16 ip6[8];
|
||||
} addr;
|
||||
struct addr_pool *next;
|
||||
__wasi_addr_type_t type;
|
||||
uint8 mask;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,29 +7,123 @@
|
|||
#include "platform_api_extension.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
static void
|
||||
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out)
|
||||
static bool
|
||||
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out,
|
||||
socklen_t *out_len)
|
||||
{
|
||||
struct sockaddr_in *v4;
|
||||
struct sockaddr_in6 *v6;
|
||||
|
||||
assert(textual);
|
||||
|
||||
out->sin_family = AF_INET;
|
||||
out->sin_port = htons(port);
|
||||
out->sin_addr.s_addr = inet_addr(textual);
|
||||
v4 = (struct sockaddr_in *)out;
|
||||
if (inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) {
|
||||
v4->sin_family = AF_INET;
|
||||
v4->sin_port = htons(port);
|
||||
*out_len = sizeof(struct sockaddr_in);
|
||||
return true;
|
||||
}
|
||||
|
||||
v6 = (struct sockaddr_in6 *)out;
|
||||
if (inet_pton(AF_INET6, textual, &v6->sin6_addr.s6_addr) == 1) {
|
||||
v6->sin6_family = AF_INET6;
|
||||
v6->sin6_port = htons(port);
|
||||
*out_len = sizeof(struct sockaddr_in6);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen,
|
||||
bh_sockaddr_t *bh_sockaddr)
|
||||
{
|
||||
switch (sockaddr->sa_family) {
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr;
|
||||
|
||||
assert(socklen >= sizeof(struct sockaddr_in));
|
||||
|
||||
bh_sockaddr->port = ntohs(addr->sin_port);
|
||||
bh_sockaddr->addr_bufer.ipv4 = ntohl(addr->sin_addr.s_addr);
|
||||
bh_sockaddr->is_ipv4 = true;
|
||||
return BHT_OK;
|
||||
}
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr;
|
||||
size_t i;
|
||||
|
||||
assert(socklen >= sizeof(struct sockaddr_in6));
|
||||
|
||||
bh_sockaddr->port = ntohs(addr->sin6_port);
|
||||
|
||||
for (i = 0; i < sizeof(bh_sockaddr->addr_bufer.ipv6)
|
||||
/ sizeof(bh_sockaddr->addr_bufer.ipv6[0]);
|
||||
i++) {
|
||||
uint16 part_addr = addr->sin6_addr.s6_addr[i * 2]
|
||||
| (addr->sin6_addr.s6_addr[i * 2 + 1] << 8);
|
||||
bh_sockaddr->addr_bufer.ipv6[i] = ntohs(part_addr);
|
||||
}
|
||||
|
||||
bh_sockaddr->is_ipv4 = false;
|
||||
return BHT_OK;
|
||||
}
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bh_sockaddr_to_sockaddr(const bh_sockaddr_t *bh_sockaddr,
|
||||
struct sockaddr_storage *sockaddr, socklen_t *socklen)
|
||||
{
|
||||
if (bh_sockaddr->is_ipv4) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr;
|
||||
addr->sin_port = htons(bh_sockaddr->port);
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = htonl(bh_sockaddr->addr_bufer.ipv4);
|
||||
*socklen = sizeof(*addr);
|
||||
}
|
||||
else {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr;
|
||||
size_t i;
|
||||
addr->sin6_port = htons(bh_sockaddr->port);
|
||||
addr->sin6_family = AF_INET6;
|
||||
|
||||
for (i = 0; i < sizeof(bh_sockaddr->addr_bufer.ipv6)
|
||||
/ sizeof(bh_sockaddr->addr_bufer.ipv6[0]);
|
||||
i++) {
|
||||
uint16 part_addr = htons(bh_sockaddr->addr_bufer.ipv6[i]);
|
||||
addr->sin6_addr.s6_addr[i * 2] = 0xff & part_addr;
|
||||
addr->sin6_addr.s6_addr[i * 2 + 1] = (0xff00 & part_addr) >> 8;
|
||||
}
|
||||
|
||||
*socklen = sizeof(*addr);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
|
||||
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
|
||||
{
|
||||
int af = is_ipv4 ? AF_INET : AF_INET6;
|
||||
|
||||
if (!sock) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
if (1 == tcp_or_udp) {
|
||||
*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (is_tcp) {
|
||||
*sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
else if (0 == tcp_or_udp) {
|
||||
*sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
else {
|
||||
*sock = socket(af, SOCK_DGRAM, 0);
|
||||
}
|
||||
|
||||
return (*sock == -1) ? BHT_ERROR : BHT_OK;
|
||||
|
@ -38,7 +132,7 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp)
|
|||
int
|
||||
os_socket_bind(bh_socket_t socket, const char *host, int *port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_storage addr = { 0 };
|
||||
struct linger ling;
|
||||
socklen_t socklen;
|
||||
int ret;
|
||||
|
@ -59,11 +153,12 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
addr.sin_port = htons(*port);
|
||||
addr.sin_family = AF_INET;
|
||||
if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr,
|
||||
&socklen)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr));
|
||||
ret = bind(socket, (struct sockaddr *)&addr, socklen);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -73,7 +168,9 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
*port = ntohs(addr.sin_port);
|
||||
*port = ntohs(addr.ss_family == AF_INET
|
||||
? ((struct sockaddr_in *)&addr)->sin_port
|
||||
: ((struct sockaddr_in6 *)&addr)->sin6_port);
|
||||
|
||||
return BHT_OK;
|
||||
|
||||
|
@ -114,7 +211,7 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
|
|||
struct sockaddr addr_tmp;
|
||||
unsigned int len = sizeof(struct sockaddr);
|
||||
|
||||
*sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len);
|
||||
*sock = accept(server_sock, &addr_tmp, &len);
|
||||
|
||||
if (*sock < 0) {
|
||||
return BHT_ERROR;
|
||||
|
@ -126,11 +223,14 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
|
|||
int
|
||||
os_socket_connect(bh_socket_t socket, const char *addr, int port)
|
||||
{
|
||||
struct sockaddr_in addr_in = { 0 };
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_storage addr_in = { 0 };
|
||||
socklen_t addr_len;
|
||||
int ret = 0;
|
||||
|
||||
textual_addr_to_sockaddr(addr, port, &addr_in);
|
||||
if (!textual_addr_to_sockaddr(addr, port, (struct sockaddr *)&addr_in,
|
||||
&addr_len)) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
ret = connect(socket, (struct sockaddr *)&addr_in, addr_len);
|
||||
if (ret == -1) {
|
||||
|
@ -146,12 +246,48 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
|
|||
return recv(socket, buf, len, 0);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags,
|
||||
bh_sockaddr_t *src_addr)
|
||||
{
|
||||
struct sockaddr_storage sock_addr = { 0 };
|
||||
socklen_t socklen = sizeof(sock_addr);
|
||||
int ret;
|
||||
|
||||
ret = recvfrom(socket, buf, len, flags, (struct sockaddr *)&sock_addr,
|
||||
&socklen);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (src_addr) {
|
||||
sockaddr_to_bh_sockaddr((struct sockaddr *)&sock_addr, socklen,
|
||||
src_addr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
|
||||
{
|
||||
return send(socket, buf, len, 0);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len,
|
||||
int flags, const bh_sockaddr_t *dest_addr)
|
||||
{
|
||||
struct sockaddr_storage sock_addr = { 0 };
|
||||
socklen_t socklen = 0;
|
||||
|
||||
bh_sockaddr_to_sockaddr(dest_addr, &sock_addr, &socklen);
|
||||
|
||||
return sendto(socket, buf, len, 0, (const struct sockaddr *)&sock_addr,
|
||||
socklen);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_close(bh_socket_t socket)
|
||||
{
|
||||
|
@ -167,12 +303,668 @@ os_socket_shutdown(bh_socket_t socket)
|
|||
}
|
||||
|
||||
int
|
||||
os_socket_inet_network(const char *cp, uint32 *out)
|
||||
os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out)
|
||||
{
|
||||
if (!cp)
|
||||
return BHT_ERROR;
|
||||
|
||||
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
|
||||
*out = ntohl(inet_addr(cp));
|
||||
if (is_ipv4) {
|
||||
if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
|
||||
out->ipv4 = ntohl(out->ipv4);
|
||||
}
|
||||
else {
|
||||
if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out->ipv6[i] = ntohs(out->ipv6[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
getaddrinfo_error_to_errno(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case EAI_AGAIN:
|
||||
return EAGAIN;
|
||||
case EAI_FAIL:
|
||||
return EFAULT;
|
||||
case EAI_MEMORY:
|
||||
return ENOMEM;
|
||||
case EAI_SYSTEM:
|
||||
return errno;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
is_addrinfo_supported(struct addrinfo *info)
|
||||
{
|
||||
return
|
||||
// Allow only IPv4 and IPv6
|
||||
(info->ai_family == AF_INET || info->ai_family == AF_INET6)
|
||||
// Allow only UDP and TCP
|
||||
&& (info->ai_socktype == SOCK_DGRAM || info->ai_socktype == SOCK_STREAM)
|
||||
&& (info->ai_protocol == IPPROTO_TCP
|
||||
|| info->ai_protocol == IPPROTO_UDP);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_resolve(const char *host, const char *service,
|
||||
uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4,
|
||||
bh_addr_info_t *addr_info, size_t addr_info_size,
|
||||
size_t *max_info_size)
|
||||
{
|
||||
struct addrinfo hints = { 0 }, *res, *result;
|
||||
int hints_enabled = hint_is_tcp || hint_is_ipv4;
|
||||
int ret;
|
||||
size_t pos = 0;
|
||||
|
||||
if (hints_enabled) {
|
||||
if (hint_is_ipv4) {
|
||||
hints.ai_family = *hint_is_ipv4 ? AF_INET : AF_INET6;
|
||||
}
|
||||
if (hint_is_tcp) {
|
||||
hints.ai_socktype = *hint_is_tcp ? SOCK_STREAM : SOCK_DGRAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = getaddrinfo(host, strlen(service) == 0 ? NULL : service,
|
||||
hints_enabled ? &hints : NULL, &result);
|
||||
if (ret != BHT_OK) {
|
||||
errno = getaddrinfo_error_to_errno(ret);
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
res = result;
|
||||
while (res) {
|
||||
if (addr_info_size > pos) {
|
||||
if (!is_addrinfo_supported(res)) {
|
||||
res = res->ai_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
sockaddr_to_bh_sockaddr(res->ai_addr, sizeof(struct sockaddr_in),
|
||||
&addr_info[pos].sockaddr);
|
||||
|
||||
addr_info[pos].is_tcp = res->ai_socktype == SOCK_STREAM;
|
||||
}
|
||||
|
||||
pos++;
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
*max_info_size = pos;
|
||||
freeaddrinfo(result);
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
os_socket_setbooloption(bh_socket_t socket, int level, int optname,
|
||||
bool is_enabled)
|
||||
{
|
||||
int option = (int)is_enabled;
|
||||
if (setsockopt(socket, level, optname, &option, sizeof(option)) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
os_socket_getbooloption(bh_socket_t socket, int level, int optname,
|
||||
bool *is_enabled)
|
||||
{
|
||||
assert(is_enabled);
|
||||
|
||||
int optval;
|
||||
int optval_size = sizeof(optval);
|
||||
if (getsockopt(socket, level, optname, &optval, &optval_size) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*is_enabled = (bool)optval;
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz)
|
||||
{
|
||||
int buf_size_int = (int)bufsiz;
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buf_size_int,
|
||||
sizeof(buf_size_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz)
|
||||
{
|
||||
assert(bufsiz);
|
||||
|
||||
int buf_size_int;
|
||||
socklen_t bufsiz_len = sizeof(buf_size_int);
|
||||
if (getsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buf_size_int, &bufsiz_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*bufsiz = (size_t)buf_size_int;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz)
|
||||
{
|
||||
int buf_size_int = (int)bufsiz;
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &buf_size_int,
|
||||
sizeof(buf_size_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz)
|
||||
{
|
||||
assert(bufsiz);
|
||||
|
||||
int buf_size_int;
|
||||
socklen_t bufsiz_len = sizeof(buf_size_int);
|
||||
if (getsockopt(socket, SOL_SOCKET, SO_RCVBUF, &buf_size_int, &bufsiz_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*bufsiz = (size_t)buf_size_int;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, SOL_SOCKET, SO_KEEPALIVE,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, SOL_SOCKET, SO_KEEPALIVE,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, SOL_SOCKET, SO_REUSEADDR,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, SOL_SOCKET, SO_REUSEADDR,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, SOL_SOCKET, SO_REUSEPORT,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, SOL_SOCKET, SO_REUSEPORT,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s)
|
||||
{
|
||||
struct linger linger_opts = { .l_onoff = (int)is_enabled,
|
||||
.l_linger = linger_s };
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_LINGER, &linger_opts,
|
||||
sizeof(linger_opts))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s)
|
||||
{
|
||||
assert(is_enabled);
|
||||
assert(linger_s);
|
||||
|
||||
struct linger linger_opts;
|
||||
socklen_t linger_opts_len = sizeof(linger_opts);
|
||||
if (getsockopt(socket, SOL_SOCKET, SO_LINGER, &linger_opts,
|
||||
&linger_opts_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*linger_s = linger_opts.l_linger;
|
||||
*is_enabled = (bool)linger_opts.l_onoff;
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_NODELAY,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_NODELAY,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
#ifdef TCP_QUICKACK
|
||||
return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_QUICKACK,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
#ifdef TCP_QUICKACK
|
||||
return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_QUICKACK,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s)
|
||||
{
|
||||
int time_s_int = (int)time_s;
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &time_s_int,
|
||||
sizeof(time_s_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
return BHT_OK;
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &time_s_int,
|
||||
sizeof(time_s_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
return BHT_OK;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s)
|
||||
{
|
||||
assert(time_s);
|
||||
int time_s_int;
|
||||
socklen_t time_s_len = sizeof(time_s_int);
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &time_s_int, &time_s_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*time_s = (uint32)time_s_int;
|
||||
return BHT_OK;
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &time_s_int, &time_s_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*time_s = (uint32)time_s_int;
|
||||
return BHT_OK;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s)
|
||||
{
|
||||
int time_s_int = (int)time_s;
|
||||
#ifdef TCP_KEEPINTVL
|
||||
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &time_s_int,
|
||||
sizeof(time_s_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s)
|
||||
{
|
||||
#ifdef TCP_KEEPINTVL
|
||||
assert(time_s);
|
||||
int time_s_int;
|
||||
socklen_t time_s_len = sizeof(time_s_int);
|
||||
if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &time_s_int, &time_s_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*time_s = (uint32)time_s_int;
|
||||
return BHT_OK;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
#ifdef TCP_FASTOPEN_CONNECT
|
||||
return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
#ifdef TCP_FASTOPEN_CONNECT
|
||||
return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled)
|
||||
{
|
||||
if (ipv6) {
|
||||
return os_socket_setbooloption(socket, IPPROTO_IPV6,
|
||||
IPV6_MULTICAST_LOOP, is_enabled);
|
||||
}
|
||||
else {
|
||||
return os_socket_setbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
is_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled)
|
||||
{
|
||||
if (ipv6) {
|
||||
return os_socket_getbooloption(socket, IPPROTO_IPV6,
|
||||
IPV6_MULTICAST_LOOP, is_enabled);
|
||||
}
|
||||
else {
|
||||
return os_socket_getbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
is_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_add_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6)
|
||||
{
|
||||
assert(imr_multiaddr);
|
||||
if (is_ipv6) {
|
||||
struct ipv6_mreq mreq;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] =
|
||||
imr_multiaddr->ipv6[i];
|
||||
}
|
||||
mreq.ipv6mr_interface = imr_interface;
|
||||
if (setsockopt(socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
|
||||
sizeof(mreq))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4;
|
||||
mreq.imr_interface.s_addr = imr_interface;
|
||||
if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
|
||||
sizeof(mreq))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_drop_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6)
|
||||
{
|
||||
assert(imr_multiaddr);
|
||||
if (is_ipv6) {
|
||||
struct ipv6_mreq mreq;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] =
|
||||
imr_multiaddr->ipv6[i];
|
||||
}
|
||||
mreq.ipv6mr_interface = imr_interface;
|
||||
if (setsockopt(socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,
|
||||
sizeof(mreq))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4;
|
||||
mreq.imr_interface.s_addr = imr_interface;
|
||||
if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
|
||||
sizeof(mreq))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s)
|
||||
{
|
||||
if (setsockopt(socket, IPPROTO_IP, IP_TTL, &ttl_s, sizeof(ttl_s)) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s)
|
||||
{
|
||||
socklen_t opt_len = sizeof(ttl_s);
|
||||
if (getsockopt(socket, IPPROTO_IP, IP_TTL, ttl_s, &opt_len) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s)
|
||||
{
|
||||
if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl_s, sizeof(ttl_s))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s)
|
||||
{
|
||||
socklen_t opt_len = sizeof(ttl_s);
|
||||
if (getsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, ttl_s, &opt_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ipv6_only(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ipv6_only(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_broadcast(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, SOL_SOCKET, SO_BROADCAST,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, SOL_SOCKET, SO_BROADCAST,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout_us / 1000000UL;
|
||||
tv.tv_usec = timeout_us % 1000000UL;
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us)
|
||||
{
|
||||
struct timeval tv;
|
||||
socklen_t tv_len = sizeof(tv);
|
||||
if (getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, &tv_len) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*timeout_us = (tv.tv_sec * 1000000UL) + tv.tv_usec;
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout_us / 1000000UL;
|
||||
tv.tv_usec = timeout_us % 1000000UL;
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us)
|
||||
{
|
||||
struct timeval tv;
|
||||
socklen_t tv_len = sizeof(tv);
|
||||
if (getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, &tv_len) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*timeout_us = (tv.tv_sec * 1000000UL) + tv.tv_usec;
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
struct sockaddr_storage addr_storage = { 0 };
|
||||
socklen_t addr_len = sizeof(addr_storage);
|
||||
int ret;
|
||||
|
||||
ret = getsockname(socket, (struct sockaddr *)&addr_storage, &addr_len);
|
||||
|
||||
if (ret != BHT_OK) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len,
|
||||
sockaddr);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
struct sockaddr_storage addr_storage = { 0 };
|
||||
socklen_t addr_len = sizeof(addr_storage);
|
||||
int ret;
|
||||
|
||||
ret = getpeername(socket, (struct sockaddr *)&addr_storage, &addr_len);
|
||||
|
||||
if (ret != BHT_OK) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len,
|
||||
sockaddr);
|
||||
}
|
|
@ -292,16 +292,29 @@ os_sem_unlink(const char *name);
|
|||
* need to implement these APIs
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
uint32 ipv4;
|
||||
uint16 ipv6[8];
|
||||
uint8 data[1];
|
||||
} bh_ip_addr_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
bh_ip_addr_buffer_t addr_bufer;
|
||||
uint16 port;
|
||||
bool is_ipv4;
|
||||
} bh_sockaddr_t;
|
||||
|
||||
/**
|
||||
* Create a socket
|
||||
*
|
||||
* @param sock [OUTPUT] the pointer of socket
|
||||
* @param tcp_or_udp 1 for tcp, 0 for udp
|
||||
* @param is_ipv4 true for IPv4, false for IPv6
|
||||
* @param is_tcp true for tcp, false for udp
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_create(bh_socket_t *sock, int tcp_or_udp);
|
||||
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp);
|
||||
|
||||
/**
|
||||
* Assign the address and port to the socket
|
||||
|
@ -380,6 +393,22 @@ os_socket_connect(bh_socket_t socket, const char *addr, int port);
|
|||
int
|
||||
os_socket_recv(bh_socket_t socket, void *buf, unsigned int len);
|
||||
|
||||
/**
|
||||
* Blocking receive message from a socket.
|
||||
*
|
||||
* @param socket the socket to send message
|
||||
* @param buf the buffer to store the data
|
||||
* @param len length of the buffer, this API does not guarantee that
|
||||
* [len] bytes are received
|
||||
* @param flags control the operation
|
||||
* @param src_addr source address
|
||||
*
|
||||
* @return number of bytes sent if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags,
|
||||
bh_sockaddr_t *src_addr);
|
||||
|
||||
/**
|
||||
* Blocking send message on a socket
|
||||
*
|
||||
|
@ -392,6 +421,21 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len);
|
|||
int
|
||||
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len);
|
||||
|
||||
/**
|
||||
* Blocking send message on a socket to the target address
|
||||
*
|
||||
* @param socket the socket to send message
|
||||
* @param buf the buffer of data to be sent
|
||||
* @param len length of the buffer
|
||||
* @param flags control the operation
|
||||
* @param dest_addr target address
|
||||
*
|
||||
* @return number of bytes sent if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len,
|
||||
int flags, const bh_sockaddr_t *dest_addr);
|
||||
|
||||
/**
|
||||
* Close a socket
|
||||
*
|
||||
|
@ -416,13 +460,522 @@ os_socket_shutdown(bh_socket_t socket);
|
|||
* converts cp into a number in host byte order suitable for use as
|
||||
* an Internet network address
|
||||
*
|
||||
* @param cp a string in IPv4 numbers-and-dots notation
|
||||
* @param is_ipv4 a flag that indicates whether the string is an IPv4 or
|
||||
* IPv6 address
|
||||
*
|
||||
* @return On success, the converted address is returned.
|
||||
* @param cp a string in IPv4 numbers-and-dots notation or IPv6
|
||||
* numbers-and-colons notation
|
||||
*
|
||||
* @param out an output buffer to store binary address
|
||||
*
|
||||
* @return On success, the function returns 0.
|
||||
* If the input is invalid, -1 is returned
|
||||
*/
|
||||
int
|
||||
os_socket_inet_network(const char *cp, uint32 *out);
|
||||
os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out);
|
||||
|
||||
typedef struct {
|
||||
bh_sockaddr_t sockaddr;
|
||||
uint8_t is_tcp;
|
||||
} bh_addr_info_t;
|
||||
|
||||
/**
|
||||
* Resolve a host a hostname and a service to one or more IP addresses
|
||||
*
|
||||
* @param host a host to resolve
|
||||
*
|
||||
* @param service a service to find a port for
|
||||
*
|
||||
* @param hint_is_tcp an optional flag that determines a preferred socket type
|
||||
(TCP or UDP).
|
||||
*
|
||||
* @param hint_is_ipv4 an optional flag that determines a preferred address
|
||||
family (IPv4 or IPv6)
|
||||
*
|
||||
* @param addr_info a buffer for resolved addresses
|
||||
*
|
||||
* @param addr_info_size a size of the buffer for resolved addresses
|
||||
|
||||
* @param max_info_size a maximum number of addresses available (can be bigger
|
||||
or smaller than buffer size)
|
||||
|
||||
* @return On success, the function returns 0; otherwise, it returns -1
|
||||
*/
|
||||
int
|
||||
os_socket_addr_resolve(const char *host, const char *service,
|
||||
uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4,
|
||||
bh_addr_info_t *addr_info, size_t addr_info_size,
|
||||
size_t *max_info_size);
|
||||
|
||||
/**
|
||||
* Returns an binary address and a port of the local socket
|
||||
*
|
||||
* @param socket the local socket
|
||||
*
|
||||
* @param sockaddr a buffer for storing the address
|
||||
*
|
||||
* @return On success, returns 0; otherwise, it returns -1.
|
||||
*/
|
||||
int
|
||||
os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr);
|
||||
|
||||
/**
|
||||
* Returns an binary address and a port of the remote socket
|
||||
*
|
||||
* @param socket the remote socket
|
||||
*
|
||||
* @param sockaddr a buffer for storing the address
|
||||
*
|
||||
* @return On success, returns 0; otherwise, it returns -1.
|
||||
*/
|
||||
int
|
||||
os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr);
|
||||
|
||||
/**
|
||||
* Set the maximum send buffer size.
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param bufsiz requested kernel buffer size
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz);
|
||||
|
||||
/**
|
||||
* Get the maximum send buffer size.
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param bufsiz the returned kernel buffer size
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz);
|
||||
|
||||
/**
|
||||
* Set the maximum receive buffer size.
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param bufsiz requested kernel buffer size
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz);
|
||||
|
||||
/**
|
||||
* Get the maximum receive buffer size.
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param bufsiz the returned kernel buffer size
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz);
|
||||
|
||||
/**
|
||||
* Enable sending of keep-alive messages on connection-oriented sockets
|
||||
*
|
||||
* @param socket the socket to set the flag
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Get if sending of keep-alive messages on connection-oriented sockets is
|
||||
* enabled
|
||||
*
|
||||
* @param socket the socket to check
|
||||
* @param is_enabled 1 if enabled or 0 if disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled);
|
||||
|
||||
/**
|
||||
* Set the send timeout until reporting an error
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param time_us microseconds until timeout
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us);
|
||||
|
||||
/**
|
||||
* Get the send timeout until reporting an error
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param time_us the returned microseconds until timeout
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us);
|
||||
|
||||
/**
|
||||
* Set the recv timeout until reporting an error
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param time_us microseconds until timeout
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us);
|
||||
|
||||
/**
|
||||
* Get the recv timeout until reporting an error
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param time_us the returned microseconds until timeout
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us);
|
||||
|
||||
/**
|
||||
* Enable re-use of local addresses
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Get whether re-use of local addresses is enabled
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param is_enabled 1 for enabled or 0 for disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled);
|
||||
|
||||
/**
|
||||
* Enable re-use of local ports
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Get whether re-use of local ports is enabled
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param is_enabled 1 for enabled or 0 for disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled);
|
||||
|
||||
/**
|
||||
* Set the linger options for the given socket
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param is_enabled whether linger is enabled
|
||||
* @param linger_s linger time (seconds)
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s);
|
||||
|
||||
/**
|
||||
* Get the linger options for the given socket
|
||||
*
|
||||
* @param socket the socket to get
|
||||
* @param is_enabled whether linger is enabled
|
||||
* @param linger_s linger time (seconds)
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s);
|
||||
|
||||
/**
|
||||
* Set no delay TCP
|
||||
* If set, disable the Nagle algorithm.
|
||||
* This means that segments are always sent as soon as possible,
|
||||
* even if there is only a small amount of data
|
||||
*
|
||||
* @param socket the socket to set the flag
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Get no delay TCP
|
||||
* If set, disable the Nagle algorithm.
|
||||
* This means that segments are always sent as soon as possible,
|
||||
* even if there is only a small amount of data
|
||||
*
|
||||
* @param socket the socket to check
|
||||
* @param is_enabled 1 if enabled or 0 if disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled);
|
||||
|
||||
/**
|
||||
* Enable/Disable tcp quickack mode
|
||||
* In quickack mode, acks are sent immediately, rather than delayed if needed in
|
||||
* accordance to normal TCP operation
|
||||
*
|
||||
* @param socket the socket to set the flag
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Enable/Disable tcp quickack mode
|
||||
* In quickack mode, acks are sent immediately, rather than delayed if needed in
|
||||
* accordance to normal TCP operation
|
||||
*
|
||||
* @param socket the socket to check
|
||||
* @param is_enabled 1 if enabled or 0 if disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled);
|
||||
|
||||
/**
|
||||
* Set the time the connection needs to remain idle before sending keepalive
|
||||
* probes
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param time_s seconds until keepalive probes are sent
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32_t time_s);
|
||||
|
||||
/**
|
||||
* Gets the time the connection needs to remain idle before sending keepalive
|
||||
* probes
|
||||
*
|
||||
* @param socket the socket to check
|
||||
* @param time_s seconds until keepalive probes are sent
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32_t *time_s);
|
||||
|
||||
/**
|
||||
* Set the time between individual keepalive probes
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param time_us seconds between individual keepalive probes
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32_t time_s);
|
||||
|
||||
/**
|
||||
* Get the time between individual keepalive probes
|
||||
*
|
||||
* @param socket the socket to get
|
||||
* @param time_s seconds between individual keepalive probes
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32_t *time_s);
|
||||
|
||||
/**
|
||||
* Set use of TCP Fast Open
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Get whether use of TCP Fast Open is enabled
|
||||
*
|
||||
* @param socket the socket to get
|
||||
* @param is_enabled 1 to enabled or 0 to disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled);
|
||||
|
||||
/**
|
||||
* Set enable or disable IPv4 or IPv6 multicast loopback.
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param ipv6 true to set ipv6 loopback or false for ipv4
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Get enable or disable IPv4 or IPv6 multicast loopback.
|
||||
*
|
||||
* @param socket the socket to check
|
||||
* @param ipv6 true to set ipv6 loopback or false for ipv4
|
||||
* @param is_enabled 1 for enabled or 0 for disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6,
|
||||
bool *is_enabled);
|
||||
|
||||
/**
|
||||
* Add membership to a group
|
||||
*
|
||||
* @param socket the socket to add membership to
|
||||
* @param imr_multiaddr the group multicast address (IPv4 or IPv6)
|
||||
* @param imr_interface the interface to join on
|
||||
* @param is_ipv6 whether the imr_multiaddr is IPv4 or IPv6 (true for IPv6)
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_ip_add_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6);
|
||||
|
||||
/**
|
||||
* Drop membership of a group
|
||||
*
|
||||
* @param socket the socket to drop membership to
|
||||
* @param imr_multiaddr the group multicast address (IPv4 or IPv6)
|
||||
* @param imr_interface the interface to join on
|
||||
* @param is_ipv6 whether the imr_multiaddr is IPv4 or IPv6 (true for IPv6)
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_ip_drop_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6);
|
||||
|
||||
/**
|
||||
* Set the current time-to-live field that is
|
||||
* used in every packet sent from this socket.
|
||||
* @param socket the socket to set the flag
|
||||
* @param ttl_s time to live (seconds)
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s);
|
||||
|
||||
/**
|
||||
* Retrieve the current time-to-live field that is
|
||||
* used in every packet sent from this socket.
|
||||
* @param socket the socket to set the flag
|
||||
* @param ttl_s time to live (seconds)
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s);
|
||||
|
||||
/**
|
||||
* Set the time-to-live value of outgoing multicast
|
||||
* packets for this socket
|
||||
* @param socket the socket to set the flag
|
||||
* @param ttl_s time to live (seconds)
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s);
|
||||
|
||||
/**
|
||||
* Read the time-to-live value of outgoing multicast
|
||||
* packets for this socket
|
||||
* @param socket the socket to set the flag
|
||||
* @param ttl_s time to live (seconds)
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s);
|
||||
|
||||
/**
|
||||
* Restrict to sending and receiving IPv6 packets only
|
||||
*
|
||||
* @param socket the socket to set
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_ipv6_only(bh_socket_t socket, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Get whether only sending and receiving IPv6 packets
|
||||
*
|
||||
* @param socket the socket to check
|
||||
* @param is_enabled 1 for enabled or 0 for disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_ipv6_only(bh_socket_t socket, bool *is_enabled);
|
||||
|
||||
/**
|
||||
* Set whether broadcast is enabled
|
||||
* When enabled, datagram sockets are allowed
|
||||
* to send packets to a broadcast address.
|
||||
*
|
||||
* @param socket the socket to set the flag
|
||||
* @param is_enabled 1 to enable or 0 to disable
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_set_broadcast(bh_socket_t socket, bool is_enabled);
|
||||
|
||||
/**
|
||||
* Get whether broadcast is enabled
|
||||
* When enabled, datagram sockets are allowed
|
||||
* to send packets to a broadcast address.
|
||||
*
|
||||
* @param socket the socket to check
|
||||
* @param is_enabled 1 if enabled or 0 if disabled
|
||||
*
|
||||
* @return 0 if success, -1 otherwise
|
||||
*/
|
||||
int
|
||||
os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
#include "platform_api_vmcore.h"
|
||||
#include "platform_api_extension.h"
|
||||
|
||||
#ifndef SGX_DISABLE_WASI
|
||||
|
||||
|
@ -91,7 +92,7 @@ swap16(uint8 *pData)
|
|||
*(pData + 1) = value;
|
||||
}
|
||||
|
||||
static uint32
|
||||
uint32
|
||||
htonl(uint32 value)
|
||||
{
|
||||
uint32 ret;
|
||||
|
@ -104,13 +105,13 @@ htonl(uint32 value)
|
|||
return value;
|
||||
}
|
||||
|
||||
static uint32
|
||||
uint32
|
||||
ntohl(uint32 value)
|
||||
{
|
||||
return htonl(value);
|
||||
}
|
||||
|
||||
static uint16
|
||||
uint16
|
||||
htons(uint16 value)
|
||||
{
|
||||
uint16 ret;
|
||||
|
@ -131,57 +132,96 @@ ntohs(uint16 value)
|
|||
|
||||
/* Coming from musl, under MIT license */
|
||||
static int
|
||||
__inet_aton(const char *s0, struct in_addr *dest)
|
||||
hexval(unsigned c)
|
||||
{
|
||||
const char *s = s0;
|
||||
unsigned char *d = (void *)dest;
|
||||
unsigned long a[4] = { 0 };
|
||||
char *z;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
a[i] = strtoul(s, &z, 0);
|
||||
if (z == s || (*z && *z != '.') || !isdigit(*s))
|
||||
return 0;
|
||||
if (!*z)
|
||||
break;
|
||||
s = z + 1;
|
||||
}
|
||||
if (i == 4)
|
||||
return 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
a[1] = a[0] & 0xffffff;
|
||||
a[0] >>= 24;
|
||||
case 1:
|
||||
a[2] = a[1] & 0xffff;
|
||||
a[1] >>= 16;
|
||||
case 2:
|
||||
a[3] = a[2] & 0xff;
|
||||
a[2] >>= 8;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (a[i] > 255)
|
||||
return 0;
|
||||
d[i] = a[i];
|
||||
}
|
||||
return 1;
|
||||
if (c - '0' < 10)
|
||||
return c - '0';
|
||||
c |= 32;
|
||||
if (c - 'a' < 6)
|
||||
return c - 'a' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Coming from musl, under MIT license */
|
||||
static int
|
||||
inet_addr(const char *p)
|
||||
inet_pton(int af, const char *restrict s, void *restrict a0)
|
||||
{
|
||||
struct in_addr a;
|
||||
if (!__inet_aton(p, &a))
|
||||
uint16_t ip[8];
|
||||
unsigned char *a = a0;
|
||||
int i, j, v, d, brk = -1, need_v4 = 0;
|
||||
|
||||
if (af == AF_INET) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (v = j = 0; j < 3 && isdigit(s[j]); j++)
|
||||
v = 10 * v + s[j] - '0';
|
||||
if (j == 0 || (j > 1 && s[0] == '0') || v > 255)
|
||||
return 0;
|
||||
a[i] = v;
|
||||
if (s[j] == 0 && i == 3)
|
||||
return 1;
|
||||
if (s[j] != '.')
|
||||
return 0;
|
||||
s += j + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (af != AF_INET6) {
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
return a.s_addr;
|
||||
}
|
||||
|
||||
if (*s == ':' && *++s != ':')
|
||||
return 0;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
if (s[0] == ':' && brk < 0) {
|
||||
brk = i;
|
||||
ip[i & 7] = 0;
|
||||
if (!*++s)
|
||||
break;
|
||||
if (i == 7)
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++)
|
||||
v = 16 * v + d;
|
||||
if (j == 0)
|
||||
return 0;
|
||||
ip[i & 7] = v;
|
||||
if (!s[j] && (brk >= 0 || i == 7))
|
||||
break;
|
||||
if (i == 7)
|
||||
return 0;
|
||||
if (s[j] != ':') {
|
||||
if (s[j] != '.' || (i < 6 && brk < 0))
|
||||
return 0;
|
||||
need_v4 = 1;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
s += j + 1;
|
||||
}
|
||||
if (brk >= 0) {
|
||||
memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk));
|
||||
for (j = 0; j < 7 - i; j++)
|
||||
ip[brk + j] = 0;
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
*a++ = ip[j] >> 8;
|
||||
*a++ = ip[j];
|
||||
}
|
||||
if (need_v4 && inet_pton(AF_INET, (void *)s, a - 4) <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
inet_network(const char *p)
|
||||
inet_addr(const char *p)
|
||||
{
|
||||
return ntohl(inet_addr(p));
|
||||
struct in_addr a;
|
||||
if (!inet_pton(AF_INET, p, &a))
|
||||
return -1;
|
||||
return a.s_addr;
|
||||
}
|
||||
/** In-enclave implementation of POSIX functions end **/
|
||||
|
||||
|
@ -527,21 +567,30 @@ os_socket_connect(bh_socket_t socket, const char *addr, int port)
|
|||
}
|
||||
|
||||
int
|
||||
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
|
||||
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
|
||||
{
|
||||
int af;
|
||||
|
||||
if (!sock) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
if (1 == tcp_or_udp) {
|
||||
if (ocall_socket(sock, AF_INET, SOCK_STREAM, IPPROTO_TCP)
|
||||
!= SGX_SUCCESS) {
|
||||
if (is_ipv4) {
|
||||
af = AF_INET;
|
||||
}
|
||||
else {
|
||||
errno = ENOSYS;
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
if (is_tcp) {
|
||||
if (ocall_socket(sock, af, SOCK_STREAM, IPPROTO_TCP) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == tcp_or_udp) {
|
||||
if (ocall_socket(sock, AF_INET, SOCK_DGRAM, 0) != SGX_SUCCESS) {
|
||||
else {
|
||||
if (ocall_socket(sock, af, SOCK_DGRAM, 0) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
@ -556,12 +605,26 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp)
|
|||
}
|
||||
|
||||
int
|
||||
os_socket_inet_network(const char *cp, uint32 *out)
|
||||
os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out)
|
||||
{
|
||||
if (!cp)
|
||||
return BHT_ERROR;
|
||||
|
||||
*out = inet_network(cp);
|
||||
if (is_ipv4) {
|
||||
if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
|
||||
out->ipv4 = ntohl(out->ipv4);
|
||||
}
|
||||
else {
|
||||
if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out->ipv6[i] = ntohs(out->ipv6[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
@ -598,6 +661,15 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags,
|
||||
bh_sockaddr_t *src_addr)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
|
||||
{
|
||||
|
@ -614,10 +686,354 @@ os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len,
|
||||
int flags, const bh_sockaddr_t *dest_addr)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_shutdown(bh_socket_t socket)
|
||||
{
|
||||
return shutdown(socket, O_RDWR);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_resolve(const char *host, const char *service,
|
||||
uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4,
|
||||
bh_addr_info_t *addr_info, size_t addr_info_size,
|
||||
size_t *max_info_size)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_add_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_drop_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ipv6_only(bh_socket_t socket, bool option)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ipv6_only(bh_socket_t socket, bool *option)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_broadcast(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -46,7 +46,8 @@ extern "C" {
|
|||
#define SHUT_RDWR 2
|
||||
|
||||
/* Address families. */
|
||||
#define AF_INET 2 /* IP protocol family. */
|
||||
#define AF_INET 2 /* IP protocol family. */
|
||||
#define AF_INET6 10 /* IP version 6. */
|
||||
|
||||
/* Standard well-defined IP protocols. */
|
||||
#define IPPROTO_TCP 6 /* Transmission Control Protocol. */
|
||||
|
@ -95,6 +96,15 @@ struct sockaddr {
|
|||
char sa_data[14]; /* Address data. */
|
||||
};
|
||||
|
||||
uint32_t
|
||||
ntohl(uint32_t value);
|
||||
|
||||
uint32_t
|
||||
htonl(uint32_t value);
|
||||
|
||||
uint16_t
|
||||
htons(uint16_t value);
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol);
|
||||
|
||||
|
|
|
@ -37,17 +37,27 @@ deinit_winsock()
|
|||
}
|
||||
|
||||
int
|
||||
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
|
||||
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
|
||||
{
|
||||
int af;
|
||||
|
||||
if (!sock) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
if (1 == tcp_or_udp) {
|
||||
*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (is_ipv4) {
|
||||
af = AF_INET;
|
||||
}
|
||||
else if (0 == tcp_or_udp) {
|
||||
*sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
else {
|
||||
errno = ENOSYS;
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
if (is_tcp) {
|
||||
*sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
else {
|
||||
*sock = socket(af, SOCK_DGRAM, 0);
|
||||
}
|
||||
|
||||
return (*sock == -1) ? BHT_ERROR : BHT_OK;
|
||||
|
@ -133,12 +143,30 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
|
|||
return recv(socket, buf, len, 0);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags,
|
||||
bh_sockaddr_t *src_addr)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
|
||||
{
|
||||
return send(socket, buf, len, 0);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len,
|
||||
int flags, const bh_sockaddr_t *dest_addr)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_close(bh_socket_t socket)
|
||||
{
|
||||
|
@ -154,11 +182,360 @@ os_socket_shutdown(bh_socket_t socket)
|
|||
}
|
||||
|
||||
int
|
||||
os_socket_inet_network(const char *cp, uint32 *out)
|
||||
os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out)
|
||||
{
|
||||
if (!cp)
|
||||
return BHT_ERROR;
|
||||
|
||||
*out = inet_addr(cp);
|
||||
if (is_ipv4) {
|
||||
if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
|
||||
out->ipv4 = ntohl(out->ipv4);
|
||||
}
|
||||
else {
|
||||
if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out->ipv6[i] = ntohs(out->ipv6[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_resolve(const char *host, const char *service,
|
||||
uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4,
|
||||
bh_addr_info_t *addr_info, size_t addr_info_size,
|
||||
size_t *max_info_size)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_add_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_drop_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ipv6_only(bh_socket_t socket, bool option)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ipv6_only(bh_socket_t socket, bool *option)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_broadcast(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,14 @@ should be announced first. Every IP address should be in CIRD notation.
|
|||
$ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm
|
||||
```
|
||||
|
||||
_iwasm_ also accepts list of domain names and domain name patterns for the address resolution via an option, `--allow-resolve`, to implement the capability control. Every domain that will be resolved using `sock_addr_resolve` needs to be added to the allowlist first.
|
||||
|
||||
```bash
|
||||
$ iwasm --allow-resolve=*.example.com --allow-resolve=domain.com
|
||||
```
|
||||
|
||||
The example above shows how to allow for resolving all `example.com`'s subdomains (e.g. `x.example.com`, `a.b.c.example.com`) and `domain.com` domain.
|
||||
|
||||
Refer to [socket api sample](../samples/socket-api) for more details.
|
||||
|
||||
## Intel SGX support
|
||||
|
|
|
@ -132,3 +132,16 @@ func (self *Module) SetWasiAddrPool(addrPool [][]byte) {
|
|||
}
|
||||
C.wasm_runtime_set_wasi_addr_pool(self.module, addrPoolPtr, addrPoolSize)
|
||||
}
|
||||
|
||||
/* Set module's wasi domain lookup pool */
|
||||
func(self *Module) SetWasiNsLookupPool(nsLookupPool[][] byte)
|
||||
{
|
||||
var nsLookupPoolPtr **C.char
|
||||
var nsLookupPoolSize C.uint
|
||||
|
||||
if (nsLookupPool != nil) {
|
||||
nsLookupPoolPtr = (**C.char)(unsafe.Pointer(&nsLookupPool[0]))
|
||||
nsLookupPoolSize = C.uint(len(nsLookupPool))
|
||||
}
|
||||
C.wasm_runtime_set_wasi_ns_lookup_pool(self.module, nsLookupPoolPtr, nsLookupPoolSize)
|
||||
}
|
|
@ -26,49 +26,54 @@ print_help()
|
|||
{
|
||||
printf("Usage: iwasm [-options] wasm_file [args...]\n");
|
||||
printf("options:\n");
|
||||
printf(" -f|--function name Specify a function name of the module to run rather\n"
|
||||
" than main\n");
|
||||
printf(" -f|--function name Specify a function name of the module to run rather\n"
|
||||
" than main\n");
|
||||
#if WASM_ENABLE_LOG != 0
|
||||
printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n"
|
||||
" level with more log\n");
|
||||
printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n"
|
||||
" level with more log\n");
|
||||
#endif
|
||||
printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n");
|
||||
printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n");
|
||||
printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n");
|
||||
printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n");
|
||||
#if WASM_ENABLE_FAST_JIT != 0
|
||||
printf(" --jit-codecache-size=n Set fast jit maximum code cache size in bytes,\n");
|
||||
printf(" default is %u KB\n", FAST_JIT_DEFAULT_CODE_CACHE_SIZE / 1024);
|
||||
printf(" --jit-codecache-size=n Set fast jit maximum code cache size in bytes,\n");
|
||||
printf(" default is %u KB\n", FAST_JIT_DEFAULT_CODE_CACHE_SIZE / 1024);
|
||||
#endif
|
||||
printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
|
||||
" that runs commands in the form of \"FUNC ARG...\"\n");
|
||||
printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
|
||||
" that runs commands in the form of \"FUNC ARG...\"\n");
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n");
|
||||
printf(" to the program, for example:\n");
|
||||
printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n");
|
||||
printf(" --dir=<dir> Grant wasi access to the given host directories\n");
|
||||
printf(" to the program, for example:\n");
|
||||
printf(" --dir=<dir1> --dir=<dir2>\n");
|
||||
printf(" --addr-pool=<addrs> Grant wasi access to the given network addresses in\n");
|
||||
printf(" CIRD notation to the program, seperated with ',',\n");
|
||||
printf(" for example:\n");
|
||||
printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n");
|
||||
printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n");
|
||||
printf(" to the program, for example:\n");
|
||||
printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n");
|
||||
printf(" --dir=<dir> Grant wasi access to the given host directories\n");
|
||||
printf(" to the program, for example:\n");
|
||||
printf(" --dir=<dir1> --dir=<dir2>\n");
|
||||
printf(" --addr-pool=<addrs> Grant wasi access to the given network addresses in\n");
|
||||
printf(" CIRD notation to the program, seperated with ',',\n");
|
||||
printf(" for example:\n");
|
||||
printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n");
|
||||
printf(" --allow-resolve=<domain> Allow the lookup of the specific domain name or domain\n");
|
||||
printf(" name suffixes using a wildcard, for example:\n");
|
||||
printf(" --allow-resolve=example.com # allow the lookup of the specific domain\n");
|
||||
printf(" --allow-resolve=*.example.com # allow the lookup of all subdomains\n");
|
||||
printf(" --allow-resolve=* # allow any lookup\n");
|
||||
#endif
|
||||
#if BH_HAS_DLFCN
|
||||
printf(" --native-lib=<lib> Register native libraries to the WASM module, which\n");
|
||||
printf(" are shared object (.so) files, for example:\n");
|
||||
printf(" --native-lib=test1.so --native-lib=test2.so\n");
|
||||
printf(" --native-lib=<lib> Register native libraries to the WASM module, which\n");
|
||||
printf(" are shared object (.so) files, for example:\n");
|
||||
printf(" --native-lib=test1.so --native-lib=test2.so\n");
|
||||
#endif
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
printf(" --module-path=<path> Indicate a module search path. default is current\n"
|
||||
" directory('./')\n");
|
||||
printf(" --module-path=<path> Indicate a module search path. default is current\n"
|
||||
" directory('./')\n");
|
||||
#endif
|
||||
#if WASM_ENABLE_LIB_PTHREAD != 0
|
||||
printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n");
|
||||
printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n");
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
printf(" -g=ip:port Set the debug sever address, default is debug disabled\n");
|
||||
printf(" if port is 0, then a random port will be used\n");
|
||||
printf(" -g=ip:port Set the debug sever address, default is debug disabled\n");
|
||||
printf(" if port is 0, then a random port will be used\n");
|
||||
#endif
|
||||
printf(" --version Show version information\n");
|
||||
printf(" --version Show version information\n");
|
||||
return 1;
|
||||
}
|
||||
/* clang-format on */
|
||||
|
@ -316,6 +321,8 @@ main(int argc, char *argv[])
|
|||
uint32 env_list_size = 0;
|
||||
const char *addr_pool[8] = { NULL };
|
||||
uint32 addr_pool_size = 0;
|
||||
const char *ns_lookup_pool[8] = { NULL };
|
||||
uint32 ns_lookup_pool_size = 0;
|
||||
#endif
|
||||
#if BH_HAS_DLFCN
|
||||
const char *native_lib_list[8] = { NULL };
|
||||
|
@ -415,6 +422,18 @@ main(int argc, char *argv[])
|
|||
token = strtok(NULL, ";");
|
||||
}
|
||||
}
|
||||
else if (!strncmp(argv[0], "--allow-resolve=", 16)) {
|
||||
if (argv[0][16] == '\0')
|
||||
return print_help();
|
||||
if (ns_lookup_pool_size
|
||||
>= sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0])) {
|
||||
printf(
|
||||
"Only allow max ns lookup number %d\n",
|
||||
(int)(sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0])));
|
||||
return 1;
|
||||
}
|
||||
ns_lookup_pool[ns_lookup_pool_size++] = argv[0] + 16;
|
||||
}
|
||||
#endif /* WASM_ENABLE_LIBC_WASI */
|
||||
#if BH_HAS_DLFCN
|
||||
else if (!strncmp(argv[0], "--native-lib=", 13)) {
|
||||
|
@ -555,6 +574,8 @@ main(int argc, char *argv[])
|
|||
env_list, env_list_size, argv, argc);
|
||||
|
||||
wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, addr_pool_size);
|
||||
wasm_runtime_set_wasi_ns_lookup_pool(wasm_module, ns_lookup_pool,
|
||||
ns_lookup_pool_size);
|
||||
#endif
|
||||
|
||||
/* instantiate the module */
|
||||
|
|
|
@ -90,6 +90,9 @@ ExternalProject_Add(wasm-app
|
|||
tcp_client.wasm ${CMAKE_BINARY_DIR}
|
||||
tcp_server.wasm ${CMAKE_BINARY_DIR}
|
||||
send_recv.wasm ${CMAKE_BINARY_DIR}
|
||||
socket_opts.wasm ${CMAKE_BINARY_DIR}
|
||||
udp_client.wasm ${CMAKE_BINARY_DIR}
|
||||
udp_server.wasm ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c)
|
||||
|
@ -100,6 +103,14 @@ add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c)
|
|||
add_executable(send_recv ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/send_recv.c)
|
||||
target_link_libraries(send_recv pthread)
|
||||
|
||||
add_executable(addr_resolve ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/addr_resolve.c)
|
||||
|
||||
add_executable(socket_opts ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/socket_opts.c)
|
||||
|
||||
add_executable(udp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/udp_client.c)
|
||||
|
||||
add_executable(udp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/udp_server.c)
|
||||
|
||||
############################################
|
||||
## Build iwasm with wasi and pthread support
|
||||
############################################
|
||||
|
|
|
@ -82,4 +82,20 @@ Data:
|
|||
And mourns for us
|
||||
```
|
||||
|
||||
`socket_opts.wasm` shows an example of getting and setting various supported socket options
|
||||
```bash
|
||||
$ ./iwasm ./socket_opts.wasm
|
||||
```
|
||||
|
||||
The output describes the different socket options that are set & retrieved, like so:
|
||||
```bash
|
||||
[Client] Create TCP socket
|
||||
[Client] Create UDP socket
|
||||
[Client] Create UDP IPv6 socket
|
||||
SO_RCVTIMEO tv_sec is expected
|
||||
SO_RCVTIMEO tv_usec is expected
|
||||
...
|
||||
[Client] Close sockets
|
||||
```
|
||||
|
||||
Refer to [socket api document](../../doc/socket_api.md) for more details.
|
||||
|
|
|
@ -79,3 +79,7 @@ endfunction()
|
|||
compile_with_clang(tcp_server.c)
|
||||
compile_with_clang(tcp_client.c)
|
||||
compile_with_clang(send_recv.c)
|
||||
compile_with_clang(addr_resolve.c)
|
||||
compile_with_clang(socket_opts.c)
|
||||
compile_with_clang(udp_client.c)
|
||||
compile_with_clang(udp_server.c)
|
||||
|
|
69
samples/socket-api/wasm-src/addr_resolve.c
Normal file
69
samples/socket-api/wasm-src/addr_resolve.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef __wasi__
|
||||
#include <wasi_socket_ext.h>
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
lookup_host(const char *host)
|
||||
{
|
||||
struct addrinfo hints, *res, *result;
|
||||
int errcode;
|
||||
char addrstr[100];
|
||||
void *ptr;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
errcode = getaddrinfo(host, NULL, &hints, &result);
|
||||
if (errcode != 0) {
|
||||
perror("getaddrinfo");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = result;
|
||||
|
||||
printf("Host: %s\n", host);
|
||||
while (res) {
|
||||
switch (res->ai_family) {
|
||||
case AF_INET:
|
||||
ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
|
||||
break;
|
||||
default:
|
||||
printf("Unsupported address family: %d\n", res->ai_family);
|
||||
continue;
|
||||
}
|
||||
inet_ntop(res->ai_family, ptr, addrstr, 100);
|
||||
printf("IPv%d address: %s (%s)\n", res->ai_family == AF_INET6 ? 6 : 4,
|
||||
addrstr, res->ai_socktype == SOCK_STREAM ? "TCP" : "UDP");
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s DOMAIN\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return lookup_host(argv[1]);
|
||||
}
|
262
samples/socket-api/wasm-src/socket_opts.c
Normal file
262
samples/socket-api/wasm-src/socket_opts.c
Normal file
|
@ -0,0 +1,262 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __wasi__
|
||||
#include <wasi_socket_ext.h>
|
||||
#endif
|
||||
|
||||
#define OPTION_ASSERT(A, B, OPTION) \
|
||||
if (A == B) { \
|
||||
printf("%s is expected\n", OPTION); \
|
||||
} \
|
||||
else { \
|
||||
printf("%s is unexpected\n", OPTION); \
|
||||
perror("assertion failed"); \
|
||||
return EXIT_FAILURE; \
|
||||
}
|
||||
|
||||
struct timeval
|
||||
to_timeval(time_t tv_sec, suseconds_t tv_usec)
|
||||
{
|
||||
struct timeval tv = { tv_sec, tv_usec };
|
||||
return tv;
|
||||
}
|
||||
|
||||
int
|
||||
set_and_get_bool_opt(int socket_fd, int level, int optname, int val)
|
||||
{
|
||||
int bool_opt = val;
|
||||
socklen_t opt_len = sizeof(bool_opt);
|
||||
setsockopt(socket_fd, level, optname, &bool_opt, sizeof(bool_opt));
|
||||
bool_opt = !bool_opt;
|
||||
getsockopt(socket_fd, level, optname, &bool_opt, &opt_len);
|
||||
return bool_opt;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int tcp_socket_fd = 0;
|
||||
int udp_socket_fd = 0;
|
||||
int udp_ipv6_socket_fd = 0;
|
||||
struct timeval tv;
|
||||
socklen_t opt_len;
|
||||
int buf_len;
|
||||
int result;
|
||||
struct linger linger_opt;
|
||||
uint32_t time_s;
|
||||
struct ip_mreq mcast;
|
||||
struct ipv6_mreq mcast_ipv6;
|
||||
unsigned char ttl;
|
||||
|
||||
printf("[Client] Create TCP socket\n");
|
||||
tcp_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (tcp_socket_fd == -1) {
|
||||
perror("Create socket failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("[Client] Create UDP socket\n");
|
||||
udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (udp_socket_fd == -1) {
|
||||
perror("Create socket failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("[Client] Create UDP IPv6 socket\n");
|
||||
udp_ipv6_socket_fd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
if (udp_ipv6_socket_fd == -1) {
|
||||
perror("Create socket failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// SO_RCVTIMEO
|
||||
tv = to_timeval(123, 1000);
|
||||
setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
tv = to_timeval(0, 0);
|
||||
opt_len = sizeof(tv);
|
||||
getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &opt_len);
|
||||
OPTION_ASSERT(tv.tv_sec, 123, "SO_RCVTIMEO tv_sec");
|
||||
OPTION_ASSERT(tv.tv_usec, 1000, "SO_RCVTIMEO tv_usec");
|
||||
|
||||
// SO_SNDTIMEO
|
||||
tv = to_timeval(456, 2000);
|
||||
setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||
tv = to_timeval(0, 0);
|
||||
opt_len = sizeof(tv);
|
||||
getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &opt_len);
|
||||
OPTION_ASSERT(tv.tv_sec, 456, "SO_SNDTIMEO tv_sec");
|
||||
OPTION_ASSERT(tv.tv_usec, 2000, "SO_SNDTIMEO tv_usec");
|
||||
|
||||
// SO_SNDBUF
|
||||
buf_len = 8192;
|
||||
setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, sizeof(buf_len));
|
||||
buf_len = 0;
|
||||
opt_len = sizeof(buf_len);
|
||||
getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, &opt_len);
|
||||
OPTION_ASSERT(buf_len, 16384, "SO_SNDBUF buf_len");
|
||||
|
||||
// SO_RCVBUF
|
||||
buf_len = 4096;
|
||||
setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, sizeof(buf_len));
|
||||
buf_len = 0;
|
||||
opt_len = sizeof(buf_len);
|
||||
getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, &opt_len);
|
||||
OPTION_ASSERT(buf_len, 8192, "SO_RCVBUF buf_len");
|
||||
|
||||
// SO_KEEPALIVE
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 1), 1,
|
||||
"SO_KEEPALIVE enabled");
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 0), 0,
|
||||
"SO_KEEPALIVE disabled");
|
||||
|
||||
// SO_REUSEADDR
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 1), 1,
|
||||
"SO_REUSEADDR enabled");
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 0), 0,
|
||||
"SO_REUSEADDR disabled");
|
||||
|
||||
// SO_REUSEPORT
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 1), 1,
|
||||
"SO_REUSEPORT enabled");
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 0), 0,
|
||||
"SO_REUSEPORT disabled");
|
||||
|
||||
// SO_LINGER
|
||||
linger_opt.l_onoff = 1;
|
||||
linger_opt.l_linger = 10;
|
||||
setsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt,
|
||||
sizeof(linger_opt));
|
||||
linger_opt.l_onoff = 0;
|
||||
linger_opt.l_linger = 0;
|
||||
opt_len = sizeof(linger_opt);
|
||||
getsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, &opt_len);
|
||||
OPTION_ASSERT(linger_opt.l_onoff, 1, "SO_LINGER l_onoff");
|
||||
OPTION_ASSERT(linger_opt.l_linger, 10, "SO_LINGER l_linger");
|
||||
|
||||
// SO_BROADCAST
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 1), 1,
|
||||
"SO_BROADCAST enabled");
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 0), 0,
|
||||
"SO_BROADCAST disabled");
|
||||
|
||||
// TCP_KEEPIDLE
|
||||
time_s = 16;
|
||||
setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s,
|
||||
sizeof(time_s));
|
||||
time_s = 0;
|
||||
opt_len = sizeof(time_s);
|
||||
getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, &opt_len);
|
||||
OPTION_ASSERT(time_s, 16, "TCP_KEEPIDLE");
|
||||
|
||||
// TCP_KEEPINTVL
|
||||
time_s = 8;
|
||||
setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s,
|
||||
sizeof(time_s));
|
||||
time_s = 0;
|
||||
opt_len = sizeof(time_s);
|
||||
getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, &opt_len);
|
||||
OPTION_ASSERT(time_s, 8, "TCP_KEEPINTVL");
|
||||
|
||||
// TCP_FASTOPEN_CONNECT
|
||||
OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP,
|
||||
TCP_FASTOPEN_CONNECT, 1),
|
||||
1, "TCP_FASTOPEN_CONNECT enabled");
|
||||
OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP,
|
||||
TCP_FASTOPEN_CONNECT, 0),
|
||||
0, "TCP_FASTOPEN_CONNECT disabled");
|
||||
|
||||
// TCP_NODELAY
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 1), 1,
|
||||
"TCP_NODELAY enabled");
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 0), 0,
|
||||
"TCP_NODELAY disabled");
|
||||
|
||||
// TCP_QUICKACK
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 1), 1,
|
||||
"TCP_QUICKACK enabled");
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 0), 0,
|
||||
"TCP_QUICKACK disabled");
|
||||
|
||||
// IP_TTL
|
||||
ttl = 8;
|
||||
setsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
|
||||
ttl = 0;
|
||||
opt_len = sizeof(ttl);
|
||||
getsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, &opt_len);
|
||||
OPTION_ASSERT(ttl, 8, "IP_TTL");
|
||||
|
||||
// IPV6_V6ONLY
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1),
|
||||
1, "IPV6_V6ONLY enabled");
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 0),
|
||||
0, "IPV6_V6ONLY disabled");
|
||||
|
||||
// IP_MULTICAST_LOOP
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 1),
|
||||
1, "IP_MULTICAST_LOOP enabled");
|
||||
OPTION_ASSERT(
|
||||
set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 0),
|
||||
0, "IP_MULTICAST_LOOP disabled");
|
||||
|
||||
// IP_ADD_MEMBERSHIP
|
||||
mcast.imr_multiaddr.s_addr = 16777440;
|
||||
mcast.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast,
|
||||
sizeof(mcast));
|
||||
OPTION_ASSERT(result, 0, "IP_ADD_MEMBERSHIP");
|
||||
|
||||
// IP_DROP_MEMBERSHIP
|
||||
result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcast,
|
||||
sizeof(mcast));
|
||||
OPTION_ASSERT(result, 0, "IP_DROP_MEMBERSHIP");
|
||||
|
||||
// IP_MULTICAST_TTL
|
||||
ttl = 8;
|
||||
setsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
|
||||
ttl = 0;
|
||||
opt_len = sizeof(ttl);
|
||||
getsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &opt_len);
|
||||
OPTION_ASSERT(ttl, 8, "IP_MULTICAST_TTL");
|
||||
|
||||
// IPV6_MULTICAST_LOOP
|
||||
OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6,
|
||||
IPV6_MULTICAST_LOOP, 1),
|
||||
1, "IPV6_MULTICAST_LOOP enabled");
|
||||
OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6,
|
||||
IPV6_MULTICAST_LOOP, 0),
|
||||
0, "IPV6_MULTICAST_LOOP disabled");
|
||||
|
||||
// IPV6_JOIN_GROUP
|
||||
setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mcast_ipv6,
|
||||
sizeof(mcast_ipv6));
|
||||
|
||||
// IPV6_LEAVE_GROUP
|
||||
setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mcast_ipv6,
|
||||
sizeof(mcast_ipv6));
|
||||
|
||||
printf("[Client] Close sockets\n");
|
||||
close(tcp_socket_fd);
|
||||
close(udp_socket_fd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
48
samples/socket-api/wasm-src/socket_utils.h
Normal file
48
samples/socket-api/wasm-src/socket_utils.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef TCP_UTILS_H
|
||||
#define TCP_UTILS_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
sockaddr_to_string(struct sockaddr *addr, char *str, size_t len)
|
||||
{
|
||||
uint16_t port;
|
||||
char ip_string[64];
|
||||
void *addr_buf;
|
||||
int ret;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
|
||||
port = addr_in->sin_port;
|
||||
addr_buf = &addr_in->sin_addr;
|
||||
break;
|
||||
}
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
|
||||
port = addr_in6->sin6_port;
|
||||
addr_buf = &addr_in6->sin6_addr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
inet_ntop(addr->sa_family, addr_buf, ip_string,
|
||||
sizeof(ip_string) / sizeof(ip_string[0]));
|
||||
|
||||
ret = snprintf(str, len, "%s:%d", ip_string, ntohs(port));
|
||||
|
||||
return ret > 0 && (size_t)ret < len ? 0 : -1;
|
||||
}
|
||||
|
||||
#endif /* TCP_UTILS_H */
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
#include "socket_utils.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -14,34 +15,77 @@
|
|||
#include <wasi_socket_ext.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
init_sockaddr_inet(struct sockaddr_in *addr)
|
||||
{
|
||||
/* 127.0.0.1:1234 */
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(1234);
|
||||
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
static void
|
||||
init_sockaddr_inet6(struct sockaddr_in6 *addr)
|
||||
{
|
||||
/* [::1]:1234 */
|
||||
addr->sin6_family = AF_INET6;
|
||||
addr->sin6_port = htons(1234);
|
||||
addr->sin6_addr = in6addr_loopback;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int socket_fd, ret, total_size = 0;
|
||||
int socket_fd, ret, total_size = 0, af;
|
||||
char buffer[1024] = { 0 };
|
||||
struct sockaddr_in server_address = { 0 };
|
||||
char ip_string[64] = { 0 };
|
||||
socklen_t len;
|
||||
struct sockaddr_storage server_address = { 0 };
|
||||
struct sockaddr_storage local_address = { 0 };
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
|
||||
af = AF_INET6;
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
init_sockaddr_inet6((struct sockaddr_in6 *)&server_address);
|
||||
}
|
||||
else {
|
||||
af = AF_INET;
|
||||
len = sizeof(struct sockaddr_in);
|
||||
init_sockaddr_inet((struct sockaddr_in *)&server_address);
|
||||
}
|
||||
|
||||
printf("[Client] Create socket\n");
|
||||
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
socket_fd = socket(af, SOCK_STREAM, 0);
|
||||
if (socket_fd == -1) {
|
||||
perror("Create socket failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* 127.0.0.1:1234 */
|
||||
server_address.sin_family = AF_INET;
|
||||
server_address.sin_port = htons(1234);
|
||||
server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
printf("[Client] Connect socket\n");
|
||||
if (connect(socket_fd, (struct sockaddr *)&server_address,
|
||||
sizeof(server_address))
|
||||
== -1) {
|
||||
if (connect(socket_fd, (struct sockaddr *)&server_address, len) == -1) {
|
||||
perror("Connect failed");
|
||||
close(socket_fd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
len = sizeof(local_address);
|
||||
ret = getsockname(socket_fd, (struct sockaddr *)&local_address, &len);
|
||||
if (ret == -1) {
|
||||
perror("Failed to retrieve socket address");
|
||||
close(socket_fd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (sockaddr_to_string((struct sockaddr *)&local_address, ip_string,
|
||||
sizeof(ip_string) / sizeof(ip_string[0]))
|
||||
!= 0) {
|
||||
printf("[Client] failed to parse local address\n");
|
||||
close(socket_fd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("[Client] Local address is: %s\n", ip_string);
|
||||
|
||||
printf("[Client] Client receive\n");
|
||||
while (1) {
|
||||
ret = recv(socket_fd, buffer + total_size, sizeof(buffer) - total_size,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
#include "socket_utils.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
|
@ -41,29 +43,53 @@ run(void *arg)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
init_sockaddr_inet(struct sockaddr_in *addr)
|
||||
{
|
||||
/* 0.0.0.0:1234 */
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(1234);
|
||||
addr->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
static void
|
||||
init_sockaddr_inet6(struct sockaddr_in6 *addr)
|
||||
{
|
||||
/* [::]:1234 */
|
||||
addr->sin6_family = AF_INET6;
|
||||
addr->sin6_port = htons(1234);
|
||||
addr->sin6_addr = in6addr_any;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int socket_fd = -1, addrlen = 0;
|
||||
struct sockaddr_in addr = { 0 };
|
||||
int socket_fd = -1, addrlen = 0, af;
|
||||
struct sockaddr_storage addr = { 0 };
|
||||
unsigned connections = 0;
|
||||
pthread_t workers[WORKER_NUM] = { 0 };
|
||||
int client_sock_fds[WORKER_NUM] = { 0 };
|
||||
char ip_string[64];
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
|
||||
af = AF_INET6;
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
init_sockaddr_inet6((struct sockaddr_in6 *)&addr);
|
||||
}
|
||||
else {
|
||||
af = AF_INET;
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
init_sockaddr_inet((struct sockaddr_in *)&addr);
|
||||
}
|
||||
|
||||
printf("[Server] Create socket\n");
|
||||
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
socket_fd = socket(af, SOCK_STREAM, 0);
|
||||
if (socket_fd < 0) {
|
||||
perror("Create socket failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 0.0.0.0:1234 */
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(1234);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
printf("[Server] Bind socket\n");
|
||||
addrlen = sizeof(addr);
|
||||
if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
|
||||
perror("Bind failed");
|
||||
goto fail;
|
||||
|
@ -77,6 +103,7 @@ main(int argc, char *argv[])
|
|||
|
||||
printf("[Server] Wait for clients to connect ..\n");
|
||||
while (connections < WORKER_NUM) {
|
||||
addrlen = sizeof(struct sockaddr);
|
||||
client_sock_fds[connections] =
|
||||
accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
|
||||
if (client_sock_fds[connections] < 0) {
|
||||
|
@ -84,7 +111,14 @@ main(int argc, char *argv[])
|
|||
break;
|
||||
}
|
||||
|
||||
printf("[Server] Client connected\n");
|
||||
if (sockaddr_to_string((struct sockaddr *)&addr, ip_string,
|
||||
sizeof(ip_string) / sizeof(ip_string[0]))
|
||||
!= 0) {
|
||||
printf("[Server] failed to parse client address\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printf("[Server] Client connected (%s)\n", ip_string);
|
||||
if (pthread_create(&workers[connections], NULL, run,
|
||||
&client_sock_fds[connections])) {
|
||||
perror("Create a worker thread failed");
|
||||
|
|
82
samples/socket-api/wasm-src/udp_client.c
Normal file
82
samples/socket-api/wasm-src/udp_client.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __wasi__
|
||||
#include <wasi_socket_ext.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
init_sockaddr_inet(struct sockaddr_in *addr)
|
||||
{
|
||||
/* 127.0.0.1:1234 */
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(1234);
|
||||
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
static void
|
||||
init_sockaddr_inet6(struct sockaddr_in6 *addr)
|
||||
{
|
||||
/* [::1]:1234 */
|
||||
addr->sin6_family = AF_INET6;
|
||||
addr->sin6_port = htons(1234);
|
||||
addr->sin6_addr = in6addr_loopback;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int socket_fd, ret, af;
|
||||
char buffer[1024] = { 0 };
|
||||
socklen_t serverlen;
|
||||
struct sockaddr_storage server_address = { 0 };
|
||||
const char *message = "Hello from client";
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
|
||||
af = AF_INET6;
|
||||
init_sockaddr_inet6((struct sockaddr_in6 *)&server_address);
|
||||
serverlen = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
else {
|
||||
af = AF_INET;
|
||||
init_sockaddr_inet((struct sockaddr_in *)&server_address);
|
||||
serverlen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
printf("[Client] Create socket\n");
|
||||
socket_fd = socket(af, SOCK_DGRAM, 0);
|
||||
if (socket_fd == -1) {
|
||||
perror("Create socket failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("[Client] Client send\n");
|
||||
ret = sendto(socket_fd, message, strlen(message), 0,
|
||||
(struct sockaddr *)&server_address, serverlen);
|
||||
if (ret < 0) {
|
||||
close(socket_fd);
|
||||
perror("Send failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("[Client] Client receive\n");
|
||||
serverlen = sizeof(server_address);
|
||||
ret = recvfrom(socket_fd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr *)&server_address, &serverlen);
|
||||
|
||||
if (ret > 0) {
|
||||
printf("[Client] Buffer recieved: %s\n", buffer);
|
||||
}
|
||||
|
||||
close(socket_fd);
|
||||
printf("[Client] BYE \n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
120
samples/socket-api/wasm-src/udp_server.c
Normal file
120
samples/socket-api/wasm-src/udp_server.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "socket_utils.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __wasi__
|
||||
#include <wasi_socket_ext.h>
|
||||
#endif
|
||||
|
||||
#define MAX_CONNECTIONS_COUNT 5
|
||||
|
||||
static void
|
||||
init_sockaddr_inet(struct sockaddr_in *addr)
|
||||
{
|
||||
/* 0.0.0.0:1234 */
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(1234);
|
||||
addr->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
static void
|
||||
init_sockaddr_inet6(struct sockaddr_in6 *addr)
|
||||
{
|
||||
/* [::]:1234 */
|
||||
addr->sin6_family = AF_INET6;
|
||||
addr->sin6_port = htons(1234);
|
||||
addr->sin6_addr = in6addr_any;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int socket_fd = -1, af;
|
||||
socklen_t addrlen = 0;
|
||||
struct sockaddr_storage addr = { 0 };
|
||||
char *reply_message = "Hello from server";
|
||||
unsigned connections = 0;
|
||||
char ip_string[64];
|
||||
char buffer[1024];
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
|
||||
af = AF_INET6;
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
init_sockaddr_inet6((struct sockaddr_in6 *)&addr);
|
||||
}
|
||||
else {
|
||||
af = AF_INET;
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
init_sockaddr_inet((struct sockaddr_in *)&addr);
|
||||
}
|
||||
|
||||
printf("[Server] Create socket\n");
|
||||
socket_fd = socket(af, SOCK_DGRAM, 0);
|
||||
if (socket_fd < 0) {
|
||||
perror("Create socket failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printf("[Server] Bind socket\n");
|
||||
if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
|
||||
perror("Bind failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printf("[Server] Wait for clients to connect ..\n");
|
||||
while (connections < MAX_CONNECTIONS_COUNT) {
|
||||
addrlen = sizeof(addr);
|
||||
int ret = recvfrom(socket_fd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr *)&addr, &addrlen);
|
||||
if (ret < 0) {
|
||||
perror("Read failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sockaddr_to_string((struct sockaddr *)&addr, ip_string,
|
||||
sizeof(ip_string) / sizeof(ip_string[0]))
|
||||
!= 0) {
|
||||
printf("[Server] failed to parse client address\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
printf("[Server] received %d bytes from %s: %s\n", ret, ip_string,
|
||||
buffer);
|
||||
|
||||
if (sendto(socket_fd, reply_message, strlen(reply_message), 0,
|
||||
(struct sockaddr *)&addr, addrlen)
|
||||
< 0) {
|
||||
perror("Send failed");
|
||||
break;
|
||||
}
|
||||
|
||||
connections++;
|
||||
}
|
||||
|
||||
if (connections == MAX_CONNECTIONS_COUNT) {
|
||||
printf("[Server] Achieve maximum amount of connections\n");
|
||||
}
|
||||
|
||||
printf("[Server] Shuting down ..\n");
|
||||
shutdown(socket_fd, SHUT_RDWR);
|
||||
close(socket_fd);
|
||||
sleep(3);
|
||||
printf("[Server] BYE \n");
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
fail:
|
||||
printf("[Server] Shuting down ..\n");
|
||||
if (socket_fd >= 0)
|
||||
close(socket_fd);
|
||||
sleep(3);
|
||||
return EXIT_FAILURE;
|
||||
}
|
Loading…
Reference in New Issue
Block a user