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:
Wenyong Huang 2022-09-22 21:46:14 +08:00 committed by GitHub
parent 32d2d16908
commit 78b5c5b484
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 6345 additions and 438 deletions

View File

@ -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.map_dir_list, module->wasi_args.map_dir_count,
module->wasi_args.env, module->wasi_args.env_count, module->wasi_args.env, module->wasi_args.env_count,
module->wasi_args.addr_pool, module->wasi_args.addr_count, module->wasi_args.addr_pool, module->wasi_args.addr_count,
module->wasi_args.argv, module->wasi_args.argc, module->wasi_args.ns_lookup_pool,
module->wasi_args.stdio[0], module->wasi_args.stdio[1], module->wasi_args.ns_lookup_count, module->wasi_args.argv,
module->wasi_args.stdio[2], error_buf, error_buf_size)) 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; goto fail;
} }
#endif #endif

View File

@ -2328,12 +2328,8 @@ wasm_runtime_enlarge_memory(WASMModuleInstanceCommon *module,
#if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_LIBC_WASI != 0
void static WASIArguments *
wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], get_wasi_args_from_module(wasm_module_t module)
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 = NULL; 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; wasi_args = &((AOTModule *)module)->wasi_args;
#endif #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) { if (wasi_args) {
wasi_args->dir_list = dir_list; wasi_args->dir_list = dir_list;
wasi_args->dir_count = dir_count; 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[], wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
uint32 addr_pool_size) uint32 addr_pool_size)
{ {
WASIArguments *wasi_args = NULL; WASIArguments *wasi_args = get_wasi_args_from_module(module);
#if WASM_ENABLE_INTERP != 0 || WASM_ENABLE_JIT != 0
if (module->module_type == Wasm_Module_Bytecode)
wasi_args = &((WASMModule *)module)->wasi_args;
#endif
#if WASM_ENABLE_AOT != 0
if (module->module_type == Wasm_Module_AoT)
wasi_args = &((AOTModule *)module)->wasi_args;
#endif
if (wasi_args) { if (wasi_args) {
wasi_args->addr_pool = addr_pool; 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 #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 bool
wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
const char *dir_list[], uint32 dir_count, const char *dir_list[], uint32 dir_count,
const char *map_dir_list[], uint32 map_dir_count, const char *map_dir_list[], uint32 map_dir_count,
const char *env[], uint32 env_count, const char *env[], uint32 env_count,
const char *addr_pool[], uint32 addr_pool_size, 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, char *argv[], uint32 argc, int stdinfd, int stdoutfd,
int stderrfd, char *error_buf, uint32 error_buf_size) 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 **argv_list = NULL;
char *env_buf = NULL; char *env_buf = NULL;
char **env_list = NULL; char **env_list = NULL;
uint64 argv_buf_size = 0, env_buf_size = 0, total_size; char *ns_lookup_buf = NULL;
uint32 argv_buf_offset = 0, env_buf_offset = 0; char **ns_lookup_list = NULL;
uint64 argv_buf_size = 0, env_buf_size = 0;
struct fd_table *curfds = NULL; struct fd_table *curfds = NULL;
struct fd_prestats *prestats = NULL; struct fd_prestats *prestats = NULL;
struct argv_environ_values *argv_environ = NULL; struct argv_environ_values *argv_environ = NULL;
@ -2443,50 +2497,20 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst,
#endif #endif
/* process argv[0], trip the path and suffix, only keep the program name */ /* process argv[0], trip the path and suffix, only keep the program name */
for (i = 0; i < argc; i++) if (!copy_string_array((const char **)argv, argc, &argv_buf, &argv_list,
argv_buf_size += strlen(argv[i]) + 1; &argv_buf_size)) {
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)))) {
set_error_buf(error_buf, error_buf_size, set_error_buf(error_buf, error_buf_size,
"Init wasi environment failed: allocate memory failed"); "Init wasi environment failed: allocate memory failed");
goto fail; goto fail;
} }
for (i = 0; i < argc; i++) { if (!copy_string_array(env, env_count, &env_buf, &env_list,
argv_list[i] = argv_buf + argv_buf_offset; &env_buf_size)) {
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)))) {
set_error_buf(error_buf, error_buf_size, set_error_buf(error_buf, error_buf_size,
"Init wasi environment failed: allocate memory failed"); "Init wasi environment failed: allocate memory failed");
goto fail; 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))) if (!(curfds = wasm_runtime_malloc(sizeof(struct fd_table)))
|| !(prestats = wasm_runtime_malloc(sizeof(struct fd_prestats))) || !(prestats = wasm_runtime_malloc(sizeof(struct fd_prestats)))
|| !(argv_environ = || !(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->curfds = curfds;
wasi_ctx->prestats = prestats; wasi_ctx->prestats = prestats;
wasi_ctx->argv_environ = argv_environ; 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->argv_list = argv_list;
wasi_ctx->env_buf = env_buf; wasi_ctx->env_buf = env_buf;
wasi_ctx->env_list = env_list; wasi_ctx->env_list = env_list;
wasi_ctx->ns_lookup_buf = ns_lookup_buf;
wasi_ctx->ns_lookup_list = ns_lookup_list;
return true; return true;
@ -2624,6 +2657,10 @@ fail:
wasm_runtime_free(env_buf); wasm_runtime_free(env_buf);
if (env_list) if (env_list)
wasm_runtime_free(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; return false;
} }
#else /* else of WASM_ENABLE_UVWASI == 0 */ #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 *map_dir_list[], uint32 map_dir_count,
const char *env[], uint32 env_count, const char *env[], uint32 env_count,
const char *addr_pool[], uint32 addr_pool_size, 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, char *argv[], uint32 argc, int stdinfd, int stdoutfd,
int stderrfd, char *error_buf, uint32 error_buf_size) 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); wasm_runtime_free(wasi_ctx->env_buf);
if (wasi_ctx->env_list) if (wasi_ctx->env_list)
wasm_runtime_free(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); wasm_runtime_free(wasi_ctx);
} }
} }

View File

@ -363,6 +363,8 @@ typedef struct WASIContext {
struct fd_prestats *prestats; struct fd_prestats *prestats;
struct argv_environ_values *argv_environ; struct argv_environ_values *argv_environ;
struct addr_pool *addr_pool; struct addr_pool *addr_pool;
char *ns_lookup_buf;
char **ns_lookup_list;
char *argv_buf; char *argv_buf;
char **argv_list; char **argv_list;
char *env_buf; 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 *map_dir_list[], uint32 map_dir_count,
const char *env[], uint32 env_count, const char *env[], uint32 env_count,
const char *addr_pool[], uint32 addr_pool_size, 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, char *argv[], uint32 argc, int stdinfd, int stdoutfd,
int stderrfd, char *error_buf, uint32 error_buf_size); 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_API_EXTERN void
wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
uint32 addr_pool_size); 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 */ #endif /* end of WASM_ENABLE_LIBC_WASI */
#if WASM_ENABLE_REF_TYPES != 0 #if WASM_ENABLE_REF_TYPES != 0

View File

@ -376,6 +376,10 @@ WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[], wasm_runtime_set_wasi_addr_pool(wasm_module_t module, const char *addr_pool[],
uint32_t addr_pool_size); 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. * Instantiate a WASM module.
* *

View File

@ -321,6 +321,8 @@ typedef struct WASIArguments {
/* in CIDR noation */ /* in CIDR noation */
const char **addr_pool; const char **addr_pool;
uint32 addr_count; uint32 addr_count;
const char **ns_lookup_pool;
uint32 ns_lookup_count;
char **argv; char **argv;
uint32 argc; uint32 argc;
int stdio[3]; int stdio[3];

View File

@ -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.map_dir_list, module->wasi_args.map_dir_count,
module->wasi_args.env, module->wasi_args.env_count, module->wasi_args.env, module->wasi_args.env_count,
module->wasi_args.addr_pool, module->wasi_args.addr_count, module->wasi_args.addr_pool, module->wasi_args.addr_count,
module->wasi_args.argv, module->wasi_args.argc, module->wasi_args.ns_lookup_pool,
module->wasi_args.stdio[0], module->wasi_args.stdio[1], module->wasi_args.ns_lookup_count, module->wasi_args.argv,
module->wasi_args.stdio[2], error_buf, error_buf_size)) { 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; goto fail;
} }
} }

View File

@ -59,7 +59,7 @@ wasm_create_gdbserver(const char *host, int32 *port)
memset(server->receive_ctx, 0, sizeof(rsp_recv_context_t)); 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"); LOG_ERROR("wasm gdb server error: create socket failed");
goto fail; goto fail;
} }

View File

@ -6,6 +6,7 @@
#ifndef _WASI_SOCKET_EXT_H_ #ifndef _WASI_SOCKET_EXT_H_
#define _WASI_SOCKET_EXT_H_ #define _WASI_SOCKET_EXT_H_
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -20,7 +21,12 @@ typedef uint16_t __wasi_ip_port_t;
typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_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 { typedef struct __wasi_addr_ip4_t {
uint8_t n0; uint8_t n0;
uint8_t n1; uint8_t n1;
@ -30,9 +36,18 @@ typedef struct __wasi_addr_ip4_t {
typedef struct __wasi_addr_ip4_port_t { typedef struct __wasi_addr_ip4_port_t {
__wasi_addr_ip4_t addr; __wasi_addr_ip4_t addr;
__wasi_ip_port_t port; __wasi_ip_port_t port; /* host byte order */
} __wasi_addr_ip4_port_t; } __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 { typedef struct __wasi_addr_ip6_t {
uint16_t n0; uint16_t n0;
uint16_t n1; uint16_t n1;
@ -46,9 +61,17 @@ typedef struct __wasi_addr_ip6_t {
typedef struct __wasi_addr_ip6_port_t { typedef struct __wasi_addr_ip6_port_t {
__wasi_addr_ip6_t addr; __wasi_addr_ip6_t addr;
__wasi_ip_port_t port; __wasi_ip_port_t port; /* host byte order */
} __wasi_addr_ip6_port_t; } __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 { typedef struct __wasi_addr_t {
__wasi_addr_type_t kind; __wasi_addr_type_t kind;
union { union {
@ -59,6 +82,18 @@ typedef struct __wasi_addr_t {
typedef enum { INET4 = 0, INET6 } __wasi_address_family_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__ #ifdef __wasi__
/** /**
* Reimplement below POSIX APIs with __wasi_sock_XXX functions. * 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/socket.h>
* <sys/types.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 int
accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
@ -86,8 +158,37 @@ recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t ssize_t
sendmsg(int sockfd, const struct msghdr *msg, int flags); 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 int
socket(int domain, int type, int protocol); 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 #endif
/** /**
@ -115,16 +216,15 @@ __wasi_sock_accept(__wasi_fd_t fd, __wasi_fd_t *fd_new)
* either IP4 or IP6. * either IP4 or IP6.
*/ */
int32_t int32_t
__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1, __imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1)
int32_t arg2)
__attribute__((__import_module__("wasi_snapshot_preview1"), __attribute__((__import_module__("wasi_snapshot_preview1"),
__import_name__("sock_addr_local"))); __import_name__("sock_addr_local")));
static inline __wasi_errno_t 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( 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. * either IP4 or IP6.
*/ */
int32_t int32_t
__imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1, __imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1)
int32_t arg2)
__attribute__((__import_module__("wasi_snapshot_preview1"), __attribute__((__import_module__("wasi_snapshot_preview1"),
__import_name__("sock_addr_remote"))); __import_name__("sock_addr_remote")));
static inline __wasi_errno_t 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( 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 * Resolve a hostname and a service to one or more IP addresses. Service is
* and you can pass 0 (zero) in most cases, it is used a hint for protocol. * 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 * Note: This is similar to `getaddrinfo` in POSIX
* *
* When successful, the contents of the output buffer consist of a sequence of * 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 * This function fills the output buffer as much as possible, truncating the
* truncating the last address entry. It is advisable that the buffer is * entries that didn't fit into the buffer. A number of available addresses
* will be returned through the last parameter.
*/ */
int32_t int32_t
__imported_wasi_snapshot_preview1_addr_resolve(int32_t arg0, int32_t arg1, __imported_wasi_snapshot_preview1_sock_addr_resolve(int32_t arg0, int32_t arg1,
int32_t arg2, int32_t arg3, int32_t arg2, int32_t arg3,
int32_t arg4) int32_t arg4, int32_t arg5)
__attribute__((__import_module__("wasi_snapshot_preview1"), __attribute__((__import_module__("wasi_snapshot_preview1"),
__import_name__("addr_resolve"))); __import_name__("sock_addr_resolve")));
static inline __wasi_errno_t static inline __wasi_errno_t
__wasi_addr_resolve(__wasi_fd_t fd, const char *host, __wasi_ip_port_t port, __wasi_sock_addr_resolve(const char *host, const char *service,
uint8_t *buf, __wasi_size_t size) __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( return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_resolve(
(int32_t)fd, (int32_t)host, (int32_t)port, (int32_t)buf, (int32_t)size); (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); (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`) * Close a socket (this is an alias for `fd_close`)
* Note: This is similar to `close` in POSIX. * 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"))); __import_name__("sock_get_reuse_addr")));
static inline __wasi_errno_t 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) return (__wasi_errno_t)
__imported_wasi_snapshot_preview1_sock_get_reuse_addr((int32_t)fd, __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"))); __import_name__("sock_get_reuse_port")));
static inline __wasi_errno_t 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) return (__wasi_errno_t)
__imported_wasi_snapshot_preview1_sock_get_reuse_port((int32_t)fd, __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"))); __import_name__("sock_set_reuse_addr")));
static inline __wasi_errno_t 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) return (__wasi_errno_t)
__imported_wasi_snapshot_preview1_sock_set_reuse_addr((int32_t)fd, __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"))); __import_name__("sock_set_reuse_port")));
static inline __wasi_errno_t 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) return (__wasi_errno_t)
__imported_wasi_snapshot_preview1_sock_set_reuse_port((int32_t)fd, __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 * Note: This is similar to `setsockopt` in POSIX for SO_SNDBUF
*/ */
int32_t 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"), __attribute__((__import_module__("wasi_snapshot_preview1"),
__import_name__("sock_set_send_buf_size"))); __import_name__("sock_set_send_buf_size")));
static inline __wasi_errno_t 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) 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() * TODO: modify recv() and send()
* since don't want to re-compile the wasi-libc, * since don't want to re-compile the wasi-libc,

View File

@ -18,16 +18,44 @@
return -1; \ 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 */ /* addr_num and port are in network order */
static void static void
ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out) ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out)
{ {
out->kind = IPv4; out->kind = IPv4;
out->addr.ip4.port = ntohs(port); out->addr.ip4.port = ntohs(port);
out->addr.ip4.addr.n3 = (addr_num & 0xFF000000) >> 24; ipv4_addr_to_wasi_ip4_addr(addr_num, &(out->addr.ip4.addr));
out->addr.ip4.addr.n2 = (addr_num & 0x00FF0000) >> 16; }
out->addr.ip4.addr.n1 = (addr_num & 0x0000FF00) >> 8;
out->addr.ip4.addr.n0 = (addr_num & 0x000000FF); static 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 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; __wasi_errno_t ret = __WASI_ERRNO_SUCCESS;
if (AF_INET == sock_addr->sa_family) { if (AF_INET == sock_addr->sa_family) {
assert(sizeof(struct sockaddr_in) == addrlen); assert(sizeof(struct sockaddr_in) <= addrlen);
ipv4_addr_to_wasi_addr( ipv4_addr_to_wasi_addr(
((struct sockaddr_in *)sock_addr)->sin_addr.s_addr, ((struct sockaddr_in *)sock_addr)->sin_addr.s_addr,
((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr); ((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr);
} }
else if (AF_INET6 == sock_addr->sa_family) { else if (AF_INET6 == sock_addr->sa_family) {
// TODO: IPV6 assert(sizeof(struct sockaddr_in6) <= addrlen);
ret = __WASI_ERRNO_AFNOSUPPORT; 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 { else {
ret = __WASI_ERRNO_AFNOSUPPORT; ret = __WASI_ERRNO_AFNOSUPPORT;
@ -54,38 +84,52 @@ sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen,
} }
static __wasi_errno_t 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 }; switch (wasi_addr->kind) {
__wasi_errno_t error; case IPv4:
{
struct sockaddr_in sock_addr_in = { 0 };
uint32_t s_addr;
error = s_addr = (wasi_addr->addr.ip4.addr.n0 << 24)
__wasi_sock_addr_remote(fd, (uint8_t *)&wasi_addr, sizeof(wasi_addr)); | (wasi_addr->addr.ip4.addr.n1 << 16)
if (__WASI_ERRNO_SUCCESS != error) { | (wasi_addr->addr.ip4.addr.n2 << 8)
return error; | 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; return __WASI_ERRNO_SUCCESS;
} }
@ -99,9 +143,8 @@ accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
error = __wasi_sock_accept(sockfd, &new_sockfd); error = __wasi_sock_accept(sockfd, &new_sockfd);
HANDLE_ERROR(error) HANDLE_ERROR(error)
// error = sock_addr_remote(new_sockfd, addr, addrlen); error = getpeername(new_sockfd, addr, addrlen);
// HANDLE_ERROR(error) HANDLE_ERROR(error)
*addrlen = 0;
return new_sockfd; return new_sockfd;
} }
@ -221,6 +264,66 @@ sendmsg(int sockfd, const struct msghdr *msg, int flags)
return so_datalen; 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 int
socket(int domain, int type, int protocol) socket(int domain, int type, int protocol)
{ {
@ -256,3 +359,612 @@ socket(int domain, int type, int protocol)
return sockfd; 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

View File

@ -18,6 +18,7 @@
#ifndef WASMTIME_SSP_H #ifndef WASMTIME_SSP_H
#define WASMTIME_SSP_H #define WASMTIME_SSP_H
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -588,6 +589,14 @@ typedef struct __wasi_addr_ip6_port_t {
__wasi_ip_port_t port; __wasi_ip_port_t port;
} __wasi_addr_ip6_port_t; } __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 { typedef struct __wasi_addr_t {
__wasi_addr_type_t kind; __wasi_addr_type_t kind;
union { union {
@ -598,6 +607,18 @@ typedef struct __wasi_addr_t {
typedef enum { INET4 = 0, INET6 } __wasi_address_family_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) #if defined(WASMTIME_SSP_WASI_API)
#define WASMTIME_SSP_SYSCALL_NAME(name) \ #define WASMTIME_SSP_SYSCALL_NAME(name) \
asm("__wasi_" #name) asm("__wasi_" #name)
@ -995,7 +1016,7 @@ wasi_ssp_sock_addr_local(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
struct fd_table *curfds, struct fd_table *curfds,
#endif #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__)); ) __attribute__((__warn_unused_result__));
__wasi_errno_t __wasi_errno_t
@ -1003,7 +1024,7 @@ wasi_ssp_sock_addr_remote(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
struct fd_table *curfds, struct fd_table *curfds,
#endif #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__)); ) __attribute__((__warn_unused_result__));
__wasi_errno_t __wasi_errno_t
@ -1023,6 +1044,16 @@ wasi_ssp_sock_bind(
__wasi_fd_t fd, __wasi_addr_t *addr __wasi_fd_t fd, __wasi_addr_t *addr
) __attribute__((__warn_unused_result__)); ) __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_errno_t
wasi_ssp_sock_connect( wasi_ssp_sock_connect(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
@ -1049,6 +1080,18 @@ __wasi_errno_t wasmtime_ssp_sock_recv(
size_t *recv_len size_t *recv_len
) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__)); ) 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( __wasi_errno_t wasmtime_ssp_sock_send(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
struct fd_table *curfds, struct fd_table *curfds,
@ -1059,6 +1102,18 @@ __wasi_errno_t wasmtime_ssp_sock_send(
size_t *sent_len size_t *sent_len
) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__)); ) 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( __wasi_errno_t wasmtime_ssp_sock_shutdown(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
struct fd_table *curfds, struct fd_table *curfds,
@ -1066,6 +1121,315 @@ __wasi_errno_t wasmtime_ssp_sock_shutdown(
__wasi_fd_t sock __wasi_fd_t sock
) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__)); ) 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) __wasi_errno_t wasmtime_ssp_sched_yield(void)
WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__)); WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__));

View File

@ -161,6 +161,31 @@ convert_errno(int error)
return errors[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. // Converts a POSIX timespec to a CloudABI timestamp.
static __wasi_timestamp_t static __wasi_timestamp_t
convert_timespec(const struct timespec *ts) 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 __wasi_errno_t
wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id, wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id,
__wasi_timestamp_t *resolution) __wasi_timestamp_t *resolution)
@ -2852,16 +2953,26 @@ wasi_ssp_sock_addr_local(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
struct fd_table *curfds, struct fd_table *curfds,
#endif #endif
__wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len) __wasi_fd_t fd, __wasi_addr_t *addr)
{ {
struct fd_object *fo; struct fd_object *fo;
bh_sockaddr_t bh_addr;
int ret;
__wasi_errno_t error = __wasi_errno_t error =
fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0); fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0);
if (error != __WASI_ESUCCESS) if (error != __WASI_ESUCCESS)
return error; return error;
ret = os_socket_addr_local(fd_number(fo), &bh_addr);
fd_object_release(fo); 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 __wasi_errno_t
@ -2869,16 +2980,55 @@ wasi_ssp_sock_addr_remote(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
struct fd_table *curfds, struct fd_table *curfds,
#endif #endif
__wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len) __wasi_fd_t fd, __wasi_addr_t *addr)
{ {
struct fd_object *fo; struct fd_object *fo;
bh_sockaddr_t bh_addr;
int ret;
__wasi_errno_t error = __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) if (error != __WASI_ESUCCESS)
return error; return error;
ret = os_socket_addr_remote(fd_number(fo), &bh_addr);
fd_object_release(fo); 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 __wasi_errno_t
@ -2888,15 +3038,15 @@ wasi_ssp_sock_bind(
#endif #endif
__wasi_fd_t fd, __wasi_addr_t *addr) __wasi_fd_t fd, __wasi_addr_t *addr)
{ {
char buf[24] = { 0 }; char buf[48] = { 0 };
const char *format = "%u.%u.%u.%u";
struct fd_object *fo; struct fd_object *fo;
__wasi_errno_t error; __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; int ret;
snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1, if (!wasi_addr_to_string(addr, buf, sizeof(buf))) {
addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3); return __WASI_EPROTONOSUPPORT;
}
if (!addr_pool_search(addr_pool, buf)) { if (!addr_pool_search(addr_pool, buf)) {
return __WASI_EACCES; return __WASI_EACCES;
@ -2915,6 +3065,55 @@ wasi_ssp_sock_bind(
return __WASI_ESUCCESS; 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_errno_t
wasi_ssp_sock_connect( wasi_ssp_sock_connect(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
@ -2922,14 +3121,14 @@ wasi_ssp_sock_connect(
#endif #endif
__wasi_fd_t fd, __wasi_addr_t *addr) __wasi_fd_t fd, __wasi_addr_t *addr)
{ {
char buf[24] = { 0 }; char buf[48] = { 0 };
const char *format = "%u.%u.%u.%u";
struct fd_object *fo; struct fd_object *fo;
__wasi_errno_t error; __wasi_errno_t error;
int ret; int ret;
snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1, if (!wasi_addr_to_string(addr, buf, sizeof(buf))) {
addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3); return __WASI_EPROTONOSUPPORT;
}
if (!addr_pool_search(addr_pool, buf)) { if (!addr_pool_search(addr_pool, buf)) {
return __WASI_EACCES; return __WASI_EACCES;
@ -2939,7 +3138,9 @@ wasi_ssp_sock_connect(
if (error != __WASI_ESUCCESS) if (error != __WASI_ESUCCESS)
return error; 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); fd_object_release(fo);
if (BHT_OK != ret) { if (BHT_OK != ret) {
return convert_errno(errno); return convert_errno(errno);
@ -2980,7 +3181,8 @@ wasi_ssp_sock_open(
__wasi_fd_t *sockfd) __wasi_fd_t *sockfd)
{ {
bh_socket_t sock; 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; int ret;
__wasi_filetype_t wasi_type; __wasi_filetype_t wasi_type;
__wasi_rights_t max_base, max_inheriting; __wasi_rights_t max_base, max_inheriting;
@ -2988,13 +3190,7 @@ wasi_ssp_sock_open(
(void)poolfd; (void)poolfd;
if (INET4 != af) { ret = os_socket_create(&sock, is_ipv4, is_tcp);
return __WASI_EAFNOSUPPORT;
}
tcp_or_udp = SOCKET_DGRAM == socktype ? 0 : 1;
ret = os_socket_create(&sock, tcp_or_udp);
if (BHT_OK != ret) { if (BHT_OK != ret) {
return convert_errno(errno); return convert_errno(errno);
} }
@ -3029,9 +3225,24 @@ wasmtime_ssp_sock_recv(
struct fd_table *curfds, struct fd_table *curfds,
#endif #endif
__wasi_fd_t sock, void *buf, size_t buf_len, size_t *recv_len) __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; struct fd_object *fo;
__wasi_errno_t error; __wasi_errno_t error;
bh_sockaddr_t sockaddr;
int ret; int ret;
error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0); error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0);
@ -3039,12 +3250,14 @@ wasmtime_ssp_sock_recv(
return error; 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); fd_object_release(fo);
if (-1 == ret) { if (-1 == ret) {
return convert_errno(errno); return convert_errno(errno);
} }
bh_sockaddr_to_wasi_addr(&sockaddr, src_addr);
*recv_len = (size_t)ret; *recv_len = (size_t)ret;
return __WASI_ESUCCESS; return __WASI_ESUCCESS;
} }
@ -3075,6 +3288,45 @@ wasmtime_ssp_sock_send(
return __WASI_ESUCCESS; 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 __wasi_errno_t
wasmtime_ssp_sock_shutdown( wasmtime_ssp_sock_shutdown(
#if !defined(WASMTIME_SSP_STATIC_CURFDS) #if !defined(WASMTIME_SSP_STATIC_CURFDS)
@ -3220,9 +3472,8 @@ fd_prestats_destroy(struct fd_prestats *pt)
bool bool
addr_pool_init(struct addr_pool *addr_pool) addr_pool_init(struct addr_pool *addr_pool)
{ {
addr_pool->next = NULL; memset(addr_pool, 0, sizeof(*addr_pool));
addr_pool->addr = 0;
addr_pool->mask = 0;
return true; 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 *cur = addr_pool;
struct addr_pool *next; struct addr_pool *next;
bh_ip_addr_buffer_t target;
if (!addr_pool) { if (!addr_pool) {
return false; return false;
@ -3242,9 +3494,20 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
next->next = NULL; next->next = NULL;
next->mask = mask; next->mask = mask;
if (os_socket_inet_network(addr, &next->addr) != BHT_OK) {
wasm_runtime_free(next); if (os_socket_inet_network(true, addr, &target) != BHT_OK) {
return false; // 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 */ /* attach with */
@ -3255,47 +3518,106 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
return true; return true;
} }
static bool static inline size_t
compare_address(const struct addr_pool *addr_pool_entry, const char *addr) min(size_t a, size_t b)
{ {
/* host order */ return a > b ? b : a;
uint32 target; }
uint32 address = addr_pool_entry->addr;
/* 0.0.0.0 means any address */ static void
if (0 == address) { 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; 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; return false;
} }
const uint32 max_mask_value = 32; init_address_mask(maskbuf, addr_size, addr_pool_entry->mask);
/* no support for invalid mask values */
if (addr_pool_entry->mask > max_mask_value) { for (size_t i = 0; i < addr_size; i++) {
return false; 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 return true;
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;
} }
bool bool
addr_pool_search(struct addr_pool *addr_pool, const char *addr) addr_pool_search(struct addr_pool *addr_pool, const char *addr)
{ {
struct addr_pool *cur = addr_pool->next; 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) { while (cur) {
if (compare_address(cur, addr)) if (cur->type == addr_type && compare_address(cur, &target)) {
return true; return true;
}
cur = cur->next; cur = cur->next;
} }
@ -3313,3 +3635,203 @@ addr_pool_destroy(struct addr_pool *addr_pool)
cur = next; 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;
}

View File

@ -47,9 +47,13 @@ struct argv_environ_values {
}; };
struct addr_pool { struct addr_pool {
struct addr_pool *next;
/* addr and mask in host order */ /* 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; uint8 mask;
}; };

View File

@ -7,29 +7,123 @@
#include "platform_api_extension.h" #include "platform_api_extension.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
static void static bool
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out) 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); assert(textual);
out->sin_family = AF_INET; v4 = (struct sockaddr_in *)out;
out->sin_port = htons(port); if (inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) {
out->sin_addr.s_addr = inet_addr(textual); 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 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) { if (!sock) {
return BHT_ERROR; return BHT_ERROR;
} }
if (1 == tcp_or_udp) { if (is_tcp) {
*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); *sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
} }
else if (0 == tcp_or_udp) { else {
*sock = socket(AF_INET, SOCK_DGRAM, 0); *sock = socket(af, SOCK_DGRAM, 0);
} }
return (*sock == -1) ? BHT_ERROR : BHT_OK; return (*sock == -1) ? BHT_ERROR : BHT_OK;
@ -38,7 +132,7 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp)
int int
os_socket_bind(bh_socket_t socket, const char *host, int *port) os_socket_bind(bh_socket_t socket, const char *host, int *port)
{ {
struct sockaddr_in addr; struct sockaddr_storage addr = { 0 };
struct linger ling; struct linger ling;
socklen_t socklen; socklen_t socklen;
int ret; int ret;
@ -59,11 +153,12 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
goto fail; goto fail;
} }
addr.sin_addr.s_addr = inet_addr(host); if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr,
addr.sin_port = htons(*port); &socklen)) {
addr.sin_family = AF_INET; goto fail;
}
ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr)); ret = bind(socket, (struct sockaddr *)&addr, socklen);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -73,7 +168,9 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
goto fail; 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; 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; struct sockaddr addr_tmp;
unsigned int len = sizeof(struct sockaddr); 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) { if (*sock < 0) {
return BHT_ERROR; return BHT_ERROR;
@ -126,11 +223,14 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
int int
os_socket_connect(bh_socket_t socket, const char *addr, int port) os_socket_connect(bh_socket_t socket, const char *addr, int port)
{ {
struct sockaddr_in addr_in = { 0 }; struct sockaddr_storage addr_in = { 0 };
socklen_t addr_len = sizeof(struct sockaddr_in); socklen_t addr_len;
int ret = 0; 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); ret = connect(socket, (struct sockaddr *)&addr_in, addr_len);
if (ret == -1) { 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); 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 int
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
{ {
return send(socket, buf, len, 0); 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 int
os_socket_close(bh_socket_t socket) os_socket_close(bh_socket_t socket)
{ {
@ -167,12 +303,668 @@ os_socket_shutdown(bh_socket_t socket)
} }
int 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) if (!cp)
return BHT_ERROR; return BHT_ERROR;
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */ if (is_ipv4) {
*out = ntohl(inet_addr(cp)); 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; 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);
}

View File

@ -292,16 +292,29 @@ os_sem_unlink(const char *name);
* need to implement these APIs * 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 * Create a socket
* *
* @param sock [OUTPUT] the pointer of 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 * @return 0 if success, -1 otherwise
*/ */
int 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 * 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 int
os_socket_recv(bh_socket_t socket, void *buf, unsigned int len); 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 * Blocking send message on a socket
* *
@ -392,6 +421,21 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len);
int int
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len); 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 * 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 * converts cp into a number in host byte order suitable for use as
* an Internet network address * 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 * If the input is invalid, -1 is returned
*/ */
int 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 #ifdef __cplusplus
} }

View File

@ -4,6 +4,7 @@
*/ */
#include "platform_api_vmcore.h" #include "platform_api_vmcore.h"
#include "platform_api_extension.h"
#ifndef SGX_DISABLE_WASI #ifndef SGX_DISABLE_WASI
@ -91,7 +92,7 @@ swap16(uint8 *pData)
*(pData + 1) = value; *(pData + 1) = value;
} }
static uint32 uint32
htonl(uint32 value) htonl(uint32 value)
{ {
uint32 ret; uint32 ret;
@ -104,13 +105,13 @@ htonl(uint32 value)
return value; return value;
} }
static uint32 uint32
ntohl(uint32 value) ntohl(uint32 value)
{ {
return htonl(value); return htonl(value);
} }
static uint16 uint16
htons(uint16 value) htons(uint16 value)
{ {
uint16 ret; uint16 ret;
@ -131,57 +132,96 @@ ntohs(uint16 value)
/* Coming from musl, under MIT license */ /* Coming from musl, under MIT license */
static int static int
__inet_aton(const char *s0, struct in_addr *dest) hexval(unsigned c)
{ {
const char *s = s0; if (c - '0' < 10)
unsigned char *d = (void *)dest; return c - '0';
unsigned long a[4] = { 0 }; c |= 32;
char *z; if (c - 'a' < 6)
int i; return c - 'a' + 10;
return -1;
for (i = 0; i < 4; i++) {
a[i] = strtoul(s, &z, 0);
if (z == s || (*z && *z != '.') || !isdigit(*s))
return 0;
if (!*z)
break;
s = z + 1;
}
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;
} }
/* Coming from musl, under MIT license */ /* Coming from musl, under MIT license */
static int static int
inet_addr(const char *p) inet_pton(int af, const char *restrict s, void *restrict a0)
{ {
struct in_addr a; uint16_t ip[8];
if (!__inet_aton(p, &a)) 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 -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 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 **/ /** In-enclave implementation of POSIX functions end **/
@ -527,21 +567,30 @@ os_socket_connect(bh_socket_t socket, const char *addr, int port)
} }
int 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) { if (!sock) {
return BHT_ERROR; return BHT_ERROR;
} }
if (1 == tcp_or_udp) { if (is_ipv4) {
if (ocall_socket(sock, AF_INET, SOCK_STREAM, IPPROTO_TCP) af = AF_INET;
!= SGX_SUCCESS) { }
else {
errno = ENOSYS;
return BHT_ERROR;
}
if (is_tcp) {
if (ocall_socket(sock, af, SOCK_STREAM, IPPROTO_TCP) != SGX_SUCCESS) {
TRACE_OCALL_FAIL(); TRACE_OCALL_FAIL();
return -1; return -1;
} }
} }
else if (0 == tcp_or_udp) { else {
if (ocall_socket(sock, AF_INET, SOCK_DGRAM, 0) != SGX_SUCCESS) { if (ocall_socket(sock, af, SOCK_DGRAM, 0) != SGX_SUCCESS) {
TRACE_OCALL_FAIL(); TRACE_OCALL_FAIL();
return -1; return -1;
} }
@ -556,12 +605,26 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp)
} }
int 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) if (!cp)
return BHT_ERROR; 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; return BHT_OK;
} }
@ -598,6 +661,15 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
return ret; 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 int
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) 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; 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 int
os_socket_shutdown(bh_socket_t socket) os_socket_shutdown(bh_socket_t socket)
{ {
return shutdown(socket, O_RDWR); 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 #endif

View File

@ -46,7 +46,8 @@ extern "C" {
#define SHUT_RDWR 2 #define SHUT_RDWR 2
/* Address families. */ /* 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. */ /* Standard well-defined IP protocols. */
#define IPPROTO_TCP 6 /* Transmission Control Protocol. */ #define IPPROTO_TCP 6 /* Transmission Control Protocol. */
@ -95,6 +96,15 @@ struct sockaddr {
char sa_data[14]; /* Address data. */ 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 int
socket(int domain, int type, int protocol); socket(int domain, int type, int protocol);

View File

@ -37,17 +37,27 @@ deinit_winsock()
} }
int 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) { if (!sock) {
return BHT_ERROR; return BHT_ERROR;
} }
if (1 == tcp_or_udp) { if (is_ipv4) {
*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); af = AF_INET;
} }
else if (0 == tcp_or_udp) { else {
*sock = socket(AF_INET, SOCK_DGRAM, 0); 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; 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); 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 int
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
{ {
return send(socket, buf, len, 0); 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 int
os_socket_close(bh_socket_t socket) os_socket_close(bh_socket_t socket)
{ {
@ -154,11 +182,360 @@ os_socket_shutdown(bh_socket_t socket)
} }
int 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) if (!cp)
return BHT_ERROR; 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; 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;
}

View File

@ -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 --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. Refer to [socket api sample](../samples/socket-api) for more details.
## Intel SGX support ## Intel SGX support

View File

@ -132,3 +132,16 @@ func (self *Module) SetWasiAddrPool(addrPool [][]byte) {
} }
C.wasm_runtime_set_wasi_addr_pool(self.module, addrPoolPtr, addrPoolSize) 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)
}

View File

@ -26,49 +26,54 @@ print_help()
{ {
printf("Usage: iwasm [-options] wasm_file [args...]\n"); printf("Usage: iwasm [-options] wasm_file [args...]\n");
printf("options:\n"); printf("options:\n");
printf(" -f|--function name Specify a function name of the module to run rather\n" printf(" -f|--function name Specify a function name of the module to run rather\n"
" than main\n"); " than main\n");
#if WASM_ENABLE_LOG != 0 #if WASM_ENABLE_LOG != 0
printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n"
" level with more log\n"); " level with more log\n");
#endif #endif
printf(" --stack-size=n Set maximum stack 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"); printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n");
#if WASM_ENABLE_FAST_JIT != 0 #if WASM_ENABLE_FAST_JIT != 0
printf(" --jit-codecache-size=n Set fast jit maximum code cache size in bytes,\n"); 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(" default is %u KB\n", FAST_JIT_DEFAULT_CODE_CACHE_SIZE / 1024);
#endif #endif
printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
" that runs commands in the form of \"FUNC ARG...\"\n"); " that runs commands in the form of \"FUNC ARG...\"\n");
#if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_LIBC_WASI != 0
printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n"); printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n");
printf(" to the program, for example:\n"); printf(" to the program, for example:\n");
printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n");
printf(" --dir=<dir> Grant wasi access to the given host directories\n"); printf(" --dir=<dir> Grant wasi access to the given host directories\n");
printf(" to the program, for example:\n"); printf(" to the program, for example:\n");
printf(" --dir=<dir1> --dir=<dir2>\n"); printf(" --dir=<dir1> --dir=<dir2>\n");
printf(" --addr-pool=<addrs> Grant wasi access to the given network addresses in\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(" CIRD notation to the program, seperated with ',',\n");
printf(" for example:\n"); printf(" for example:\n");
printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\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 #endif
#if BH_HAS_DLFCN #if BH_HAS_DLFCN
printf(" --native-lib=<lib> Register native libraries to the WASM module, which\n"); printf(" --native-lib=<lib> Register native libraries to the WASM module, which\n");
printf(" are shared object (.so) files, for example:\n"); printf(" are shared object (.so) files, for example:\n");
printf(" --native-lib=test1.so --native-lib=test2.so\n"); printf(" --native-lib=test1.so --native-lib=test2.so\n");
#endif #endif
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0
printf(" --module-path=<path> Indicate a module search path. default is current\n" printf(" --module-path=<path> Indicate a module search path. default is current\n"
" directory('./')\n"); " directory('./')\n");
#endif #endif
#if WASM_ENABLE_LIB_PTHREAD != 0 #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 #endif
#if WASM_ENABLE_DEBUG_INTERP != 0 #if WASM_ENABLE_DEBUG_INTERP != 0
printf(" -g=ip:port Set the debug sever address, default is debug disabled\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"); printf(" if port is 0, then a random port will be used\n");
#endif #endif
printf(" --version Show version information\n"); printf(" --version Show version information\n");
return 1; return 1;
} }
/* clang-format on */ /* clang-format on */
@ -316,6 +321,8 @@ main(int argc, char *argv[])
uint32 env_list_size = 0; uint32 env_list_size = 0;
const char *addr_pool[8] = { NULL }; const char *addr_pool[8] = { NULL };
uint32 addr_pool_size = 0; uint32 addr_pool_size = 0;
const char *ns_lookup_pool[8] = { NULL };
uint32 ns_lookup_pool_size = 0;
#endif #endif
#if BH_HAS_DLFCN #if BH_HAS_DLFCN
const char *native_lib_list[8] = { NULL }; const char *native_lib_list[8] = { NULL };
@ -415,6 +422,18 @@ main(int argc, char *argv[])
token = strtok(NULL, ";"); 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 */ #endif /* WASM_ENABLE_LIBC_WASI */
#if BH_HAS_DLFCN #if BH_HAS_DLFCN
else if (!strncmp(argv[0], "--native-lib=", 13)) { else if (!strncmp(argv[0], "--native-lib=", 13)) {
@ -555,6 +574,8 @@ main(int argc, char *argv[])
env_list, env_list_size, argv, argc); env_list, env_list_size, argv, argc);
wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, addr_pool_size); 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 #endif
/* instantiate the module */ /* instantiate the module */

View File

@ -90,6 +90,9 @@ ExternalProject_Add(wasm-app
tcp_client.wasm ${CMAKE_BINARY_DIR} tcp_client.wasm ${CMAKE_BINARY_DIR}
tcp_server.wasm ${CMAKE_BINARY_DIR} tcp_server.wasm ${CMAKE_BINARY_DIR}
send_recv.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) 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) add_executable(send_recv ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/send_recv.c)
target_link_libraries(send_recv pthread) 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 ## Build iwasm with wasi and pthread support
############################################ ############################################

View File

@ -82,4 +82,20 @@ Data:
And mourns for us 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. Refer to [socket api document](../../doc/socket_api.md) for more details.

View File

@ -79,3 +79,7 @@ endfunction()
compile_with_clang(tcp_server.c) compile_with_clang(tcp_server.c)
compile_with_clang(tcp_client.c) compile_with_clang(tcp_client.c)
compile_with_clang(send_recv.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)

View 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]);
}

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

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

View File

@ -2,6 +2,7 @@
* Copyright (C) 2019 Intel Corporation. All rights reserved. * Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/ */
#include "socket_utils.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -14,34 +15,77 @@
#include <wasi_socket_ext.h> #include <wasi_socket_ext.h>
#endif #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 int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int socket_fd, ret, total_size = 0; int socket_fd, ret, total_size = 0, af;
char buffer[1024] = { 0 }; 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"); printf("[Client] Create socket\n");
socket_fd = socket(AF_INET, SOCK_STREAM, 0); socket_fd = socket(af, SOCK_STREAM, 0);
if (socket_fd == -1) { if (socket_fd == -1) {
perror("Create socket failed"); perror("Create socket failed");
return EXIT_FAILURE; 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"); printf("[Client] Connect socket\n");
if (connect(socket_fd, (struct sockaddr *)&server_address, if (connect(socket_fd, (struct sockaddr *)&server_address, len) == -1) {
sizeof(server_address))
== -1) {
perror("Connect failed"); perror("Connect failed");
close(socket_fd); close(socket_fd);
return EXIT_FAILURE; 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"); printf("[Client] Client receive\n");
while (1) { while (1) {
ret = recv(socket_fd, buffer + total_size, sizeof(buffer) - total_size, ret = recv(socket_fd, buffer + total_size, sizeof(buffer) - total_size,

View File

@ -2,6 +2,8 @@
* Copyright (C) 2019 Intel Corporation. All rights reserved. * Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/ */
#include "socket_utils.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <pthread.h> #include <pthread.h>
@ -41,29 +43,53 @@ run(void *arg)
return NULL; 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 int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int socket_fd = -1, addrlen = 0; int socket_fd = -1, addrlen = 0, af;
struct sockaddr_in addr = { 0 }; struct sockaddr_storage addr = { 0 };
unsigned connections = 0; unsigned connections = 0;
pthread_t workers[WORKER_NUM] = { 0 }; pthread_t workers[WORKER_NUM] = { 0 };
int client_sock_fds[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"); printf("[Server] Create socket\n");
socket_fd = socket(AF_INET, SOCK_STREAM, 0); socket_fd = socket(af, SOCK_STREAM, 0);
if (socket_fd < 0) { if (socket_fd < 0) {
perror("Create socket failed"); perror("Create socket failed");
goto fail; 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"); printf("[Server] Bind socket\n");
addrlen = sizeof(addr);
if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) { if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
perror("Bind failed"); perror("Bind failed");
goto fail; goto fail;
@ -77,6 +103,7 @@ main(int argc, char *argv[])
printf("[Server] Wait for clients to connect ..\n"); printf("[Server] Wait for clients to connect ..\n");
while (connections < WORKER_NUM) { while (connections < WORKER_NUM) {
addrlen = sizeof(struct sockaddr);
client_sock_fds[connections] = client_sock_fds[connections] =
accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen); accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
if (client_sock_fds[connections] < 0) { if (client_sock_fds[connections] < 0) {
@ -84,7 +111,14 @@ main(int argc, char *argv[])
break; 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, if (pthread_create(&workers[connections], NULL, run,
&client_sock_fds[connections])) { &client_sock_fds[connections])) {
perror("Create a worker thread failed"); perror("Create a worker thread failed");

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

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