diff --git a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h index b2260d35..84b8811a 100644 --- a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h +++ b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h @@ -126,6 +126,14 @@ recvmsg(int sockfd, struct msghdr *msg, int flags); ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); +ssize_t +sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); + +ssize_t +recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen); + int socket(int domain, int type, int protocol); @@ -257,6 +265,48 @@ __wasi_sock_bind(__wasi_fd_t fd, __wasi_addr_t *addr) (int32_t)fd, (int32_t)addr); } +/** + * Send data to a specific target + * Note: This is similar to `sendto` in POSIX + */ +int32_t +__imported_wasi_snapshot_preview1_sock_send_to(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4, int32_t arg5) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_send_to"))); + +static inline __wasi_errno_t +__wasi_sock_send_to(__wasi_fd_t fd, const __wasi_ciovec_t *si_data, + uint32_t si_data_len, __wasi_siflags_t si_flags, + const __wasi_addr_t *dest_addr, uint32_t *so_data_len) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_send_to( + (int32_t)fd, (int32_t)si_data, (int32_t)si_data_len, (int32_t)si_flags, + (uint32_t)dest_addr, (uint32_t)so_data_len); +} + +/** + * Receives data from a socket + * Note: This is similar to `recvfrom` in POSIX + */ +int32_t +__imported_wasi_snapshot_preview1_sock_recv_from(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4, int32_t arg5) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_recv_from"))); + +static inline __wasi_errno_t +__wasi_sock_recv_from(__wasi_fd_t fd, __wasi_ciovec_t *ri_data, + uint32_t ri_data_len, __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, uint32_t *ro_data_len) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_recv_from( + (int32_t)fd, (int32_t)ri_data, (int32_t)ri_data_len, (int32_t)ri_flags, + (uint32_t)src_addr, (uint32_t)ro_data_len); +} + /** * Close a socket (this is an alias for `fd_close`) * Note: This is similar to `close` in POSIX. diff --git a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c index 0c85368e..bc15125f 100644 --- a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c +++ b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c @@ -59,7 +59,7 @@ sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen, ((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr); } else if (AF_INET6 == sock_addr->sa_family) { - assert(sizeof(struct sockaddr_in6) == addrlen); + assert(sizeof(struct sockaddr_in6) <= addrlen); ipv6_addr_to_wasi_addr( (uint16_t *)((struct sockaddr_in6 *)sock_addr)->sin6_addr.s6_addr, ((struct sockaddr_in6 *)sock_addr)->sin6_port, wasi_addr); @@ -252,6 +252,66 @@ sendmsg(int sockfd, const struct msghdr *msg, int flags) return so_datalen; } +ssize_t +sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + // Prepare input parameters. + __wasi_ciovec_t iov = { .buf = buf, .buf_len = len }; + uint32_t so_datalen = 0; + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + size_t si_data_len = 1; + __wasi_siflags_t si_flags = 0; + + // This implementation does not support any flags. + if (flags != 0) { + HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT) + } + + error = sockaddr_to_wasi_addr(dest_addr, addrlen, &wasi_addr); + HANDLE_ERROR(error); + + // Perform system call. + error = __wasi_sock_send_to(sockfd, &iov, si_data_len, si_flags, &wasi_addr, + &so_datalen); + HANDLE_ERROR(error) + + return so_datalen; +} + +ssize_t +recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen) +{ + // Prepare input parameters. + __wasi_ciovec_t iov = { .buf = buf, .buf_len = len }; + uint32_t so_datalen = 0; + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + size_t si_data_len = 1; + __wasi_siflags_t si_flags = 0; + + // This implementation does not support any flags. + if (flags != 0) { + HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT) + } + + if (!src_addr) { + return recv(sockfd, buf, len, flags); + } + + // Perform system call. + error = __wasi_sock_recv_from(sockfd, &iov, si_data_len, si_flags, + &wasi_addr, &so_datalen); + HANDLE_ERROR(error); + + error = wasi_addr_to_sockaddr(&wasi_addr, src_addr, addrlen); + HANDLE_ERROR(error); + + return so_datalen; +} + int socket(int domain, int type, int protocol) { diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index 78dee472..327941ca 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -1274,9 +1274,70 @@ wasi_sock_set_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, } static wasi_errno_t -wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, - uint32 ri_data_len, wasi_riflags_t ri_flags, uint32 *ro_data_len, - wasi_roflags_t *ro_flags) +allocate_iovec_app_buffer(wasm_module_inst_t module_inst, + const iovec_app_t *data, uint32 data_len, + uint8 **buf_ptr, uint64 *buf_len) +{ + uint64 total_size = 0; + uint32 i; + uint8 *buf_begin = NULL; + + if (data_len == 0) { + return __WASI_EINVAL; + } + + total_size = sizeof(iovec_app_t) * (uint64)data_len; + if (total_size >= UINT32_MAX + || !validate_native_addr((void *)data, (uint32)total_size)) + return __WASI_EINVAL; + + for (total_size = 0, i = 0; i < data_len; i++, data++) { + total_size += data->buf_len; + } + if (total_size >= UINT32_MAX + || !(buf_begin = wasm_runtime_malloc((uint32)total_size))) { + return __WASI_ENOMEM; + } + + *buf_len = total_size; + *buf_ptr = buf_begin; + + return __WASI_ESUCCESS; +} + +static wasi_errno_t +copy_buffer_to_iovec_app(wasm_module_inst_t module_inst, uint8 *buf_begin, + uint32 buf_size, iovec_app_t *data, uint32 data_len) +{ + uint8 *buf = buf_begin; + uint32 i; + + for (i = 0; i < data_len; data++, i++) { + char *native_addr; + + if (!validate_app_addr(data->buf_offset, data->buf_len)) { + return __WASI_EINVAL; + } + + if (buf >= buf_begin + buf_size + || buf + data->buf_len < buf /* integer overflow */ + || buf + data->buf_len > buf_begin + buf_size) { + break; + } + + native_addr = (void *)addr_app_to_native(data->buf_offset); + bh_memcpy_s(native_addr, data->buf_len, buf, data->buf_len); + buf += data->buf_len; + } + + return __WASI_ESUCCESS; +} + +static wasi_errno_t +wasi_sock_recv_from(wasm_exec_env_t exec_env, wasi_fd_t sock, + iovec_app_t *ri_data, uint32 ri_data_len, + wasi_riflags_t ri_flags, __wasi_addr_t *src_addr, + uint32 *ro_data_len) { /** * ri_data_len is the length of a list of iovec_app_t, which head is @@ -1286,9 +1347,6 @@ wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); uint64 total_size; - uint32 i; - iovec_app_t *ri_data_orig = ri_data; - uint8 *buf = NULL; uint8 *buf_begin = NULL; wasi_errno_t err; size_t recv_bytes = 0; @@ -1297,55 +1355,28 @@ wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, return __WASI_EINVAL; } - if (ri_data_len == 0) { - return __WASI_EINVAL; - } - - total_size = sizeof(iovec_app_t) * (uint64)ri_data_len; - if (!validate_native_addr(ro_data_len, (uint32)sizeof(uint32)) - || !validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t)) - || total_size >= UINT32_MAX - || !validate_native_addr(ri_data, (uint32)total_size)) + if (!validate_native_addr(ro_data_len, (uint32)sizeof(uint32))) return __WASI_EINVAL; - /* receive and scatter*/ - for (total_size = 0, i = 0; i < ri_data_len; i++, ri_data++) { - total_size += ri_data->buf_len; - } - if (total_size >= UINT32_MAX - || !(buf_begin = wasm_runtime_malloc((uint32)total_size))) { - return __WASI_ENOMEM; + err = allocate_iovec_app_buffer(module_inst, ri_data, ri_data_len, + &buf_begin, &total_size); + if (err != __WASI_ESUCCESS) { + goto fail; } + memset(buf_begin, 0, total_size); *ro_data_len = 0; - err = wasmtime_ssp_sock_recv(curfds, sock, buf_begin, total_size, - &recv_bytes); + err = wasmtime_ssp_sock_recv_from(curfds, sock, buf_begin, total_size, + ri_flags, src_addr, &recv_bytes); if (err != __WASI_ESUCCESS) { goto fail; } *ro_data_len = (uint32)recv_bytes; - buf = buf_begin; - ri_data = ri_data_orig; - for (i = 0; i < ri_data_len; ri_data++, i++) { - char *native_addr; + err = copy_buffer_to_iovec_app(module_inst, buf_begin, (uint32)recv_bytes, + ri_data, ri_data_len); - if ((uint32)(buf - buf_begin) >= *ro_data_len) { - break; - } - - if (!validate_app_addr(ri_data->buf_offset, ri_data->buf_len)) { - err = __WASI_EINVAL; - goto fail; - } - - native_addr = (void *)addr_app_to_native(ri_data->buf_offset); - bh_memcpy_s(native_addr, ri_data->buf_len, buf, ri_data->buf_len); - buf += ri_data->buf_len; - } - - *ro_flags = ri_flags; fail: if (buf_begin) { wasm_runtime_free(buf_begin); @@ -1353,6 +1384,59 @@ fail: return err; } +static wasi_errno_t +wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, + uint32 ri_data_len, wasi_riflags_t ri_flags, uint32 *ro_data_len, + wasi_roflags_t *ro_flags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + __wasi_addr_t src_addr; + wasi_errno_t error; + + if (!validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t))) + return __WASI_EINVAL; + + error = wasi_sock_recv_from(exec_env, sock, ri_data, ri_data_len, ri_flags, + &src_addr, ro_data_len); + *ro_flags = ri_flags; + + return error; +} + +static wasi_errno_t +convert_iovec_app_to_buffer(wasm_module_inst_t module_inst, + const iovec_app_t *si_data, uint32 si_data_len, + uint8 **buf_ptr, uint64 *buf_len) +{ + uint32 i; + const iovec_app_t *si_data_orig = si_data; + uint8 *buf = NULL; + wasi_errno_t error; + + error = allocate_iovec_app_buffer(module_inst, si_data, si_data_len, + buf_ptr, buf_len); + if (error != __WASI_ESUCCESS) { + return error; + } + + buf = *buf_ptr; + si_data = si_data_orig; + for (i = 0; i < si_data_len; i++, si_data++) { + char *native_addr; + + if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) { + wasm_runtime_free(*buf_ptr); + return __WASI_EINVAL; + } + + native_addr = (char *)addr_app_to_native(si_data->buf_offset); + bh_memcpy_s(buf, si_data->buf_len, native_addr, si_data->buf_len); + buf += si_data->buf_len; + } + + return __WASI_ESUCCESS; +} + static wasi_errno_t wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock, const iovec_app_t *si_data, uint32 si_data_len, @@ -1365,11 +1449,8 @@ wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock, wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - uint64 total_size = 0; - uint32 i; - const iovec_app_t *si_data_orig = si_data; + uint64 buf_size = 0; uint8 *buf = NULL; - uint8 *buf_begin = NULL; wasi_errno_t err; size_t send_bytes = 0; @@ -1377,49 +1458,61 @@ wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock, return __WASI_EINVAL; } - if (si_data_len == 0) { - return __WASI_EINVAL; - } - - total_size = sizeof(iovec_app_t) * (uint64)si_data_len; - if (!validate_native_addr(so_data_len, sizeof(uint32)) - || total_size >= UINT32_MAX - || !validate_native_addr((void *)si_data, (uint32)total_size)) + if (!validate_native_addr(so_data_len, sizeof(uint32))) return __WASI_EINVAL; - /* gather and send */ - for (total_size = 0, i = 0; i < si_data_len; i++, si_data++) { - total_size += si_data->buf_len; - } - if (total_size >= UINT32_MAX - || !(buf_begin = wasm_runtime_malloc((uint32)total_size))) { - return __WASI_ENOMEM; - } - - buf = buf_begin; - si_data = si_data_orig; - for (i = 0; i < si_data_len; i++, si_data++) { - char *native_addr; - - if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) { - err = __WASI_EINVAL; - goto fail; - } - - native_addr = (char *)addr_app_to_native(si_data->buf_offset); - bh_memcpy_s(buf, si_data->buf_len, native_addr, si_data->buf_len); - buf += si_data->buf_len; - } + err = convert_iovec_app_to_buffer(module_inst, si_data, si_data_len, &buf, + &buf_size); + if (err != __WASI_ESUCCESS) + return err; *so_data_len = 0; - err = wasmtime_ssp_sock_send(curfds, sock, buf_begin, total_size, - &send_bytes); + err = wasmtime_ssp_sock_send(curfds, sock, buf, buf_size, &send_bytes); *so_data_len = (uint32)send_bytes; -fail: - if (buf_begin) { - wasm_runtime_free(buf_begin); + wasm_runtime_free(buf); + + return err; +} + +static wasi_errno_t +wasi_sock_send_to(wasm_exec_env_t exec_env, wasi_fd_t sock, + const iovec_app_t *si_data, uint32 si_data_len, + wasi_siflags_t si_flags, const __wasi_addr_t *dest_addr, + uint32 *so_data_len) +{ + /** + * si_data_len is the length of a list of iovec_app_t, which head is + * si_data. so_data_len is the number of bytes sent + **/ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + uint64 buf_size = 0; + uint8 *buf = NULL; + wasi_errno_t err; + size_t send_bytes = 0; + struct addr_pool *addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx); + + if (!wasi_ctx) { + return __WASI_EINVAL; } + + if (!validate_native_addr(so_data_len, sizeof(uint32))) + return __WASI_EINVAL; + + err = convert_iovec_app_to_buffer(module_inst, si_data, si_data_len, &buf, + &buf_size); + if (err != __WASI_ESUCCESS) + return err; + + *so_data_len = 0; + err = wasmtime_ssp_sock_send_to(curfds, addr_pool, sock, buf, buf_size, + si_flags, dest_addr, &send_bytes); + *so_data_len = (uint32)send_bytes; + + wasm_runtime_free(buf); + return err; } @@ -1505,7 +1598,9 @@ static NativeSymbol native_symbols_libc_wasi[] = { REG_NATIVE_FUNC(sock_listen, "(ii)i"), REG_NATIVE_FUNC(sock_open, "(iii*)i"), REG_NATIVE_FUNC(sock_recv, "(i*ii**)i"), + REG_NATIVE_FUNC(sock_recv_from, "(i*ii**)i"), REG_NATIVE_FUNC(sock_send, "(i*ii*)i"), + REG_NATIVE_FUNC(sock_send_to, "(i*ii**)i"), REG_NATIVE_FUNC(sock_set_recv_buf_size, "(ii)i"), REG_NATIVE_FUNC(sock_set_recv_timeout, "(iI)i"), REG_NATIVE_FUNC(sock_set_reuse_addr, "(ii)i"), diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index e0b3356b..79f1375a 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -1071,6 +1071,18 @@ __wasi_errno_t wasmtime_ssp_sock_recv( size_t *recv_len ) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__)); +__wasi_errno_t wasmtime_ssp_sock_recv_from( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + void *buf, + size_t buf_len, + __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, + size_t *recv_len +) WASMTIME_SSP_SYSCALL_NAME(sock_recv_from) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasmtime_ssp_sock_send( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, @@ -1081,6 +1093,18 @@ __wasi_errno_t wasmtime_ssp_sock_send( size_t *sent_len ) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__)); +__wasi_errno_t wasmtime_ssp_sock_send_to( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t sock, + const void *buf, + size_t buf_len, + __wasi_siflags_t si_flags, + const __wasi_addr_t *dest_addr, + size_t *sent_len +) WASMTIME_SSP_SYSCALL_NAME(sock_send_to) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasmtime_ssp_sock_shutdown( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 5a884e73..9d702637 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -224,35 +224,59 @@ convert_clockid(__wasi_clockid_t in, clockid_t *out) } } -// Converts an IPv4 binary address object to WASI address. static void -ipv4_addr_to_wasi_addr(uint32_t addr, __wasi_ip_port_t port, __wasi_addr_t *out) +wasi_addr_to_bh_sockaddr(const __wasi_addr_t *wasi_addr, + bh_sockaddr_t *sockaddr) { - addr = ntohl(addr); - - out->kind = IPv4; - out->addr.ip4.port = port; - out->addr.ip4.addr.n0 = (addr & 0xFF000000) >> 24; - out->addr.ip4.addr.n1 = (addr & 0x00FF0000) >> 16; - out->addr.ip4.addr.n2 = (addr & 0x0000FF00) >> 8; - out->addr.ip4.addr.n3 = (addr & 0x000000FF); + 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 -ipv6_addr_to_wasi_addr(uint16_t addr[8], __wasi_ip_port_t port, - __wasi_addr_t *out) +bh_sockaddr_to_wasi_addr(const bh_sockaddr_t *sockaddr, + __wasi_addr_t *wasi_addr) { - out->kind = IPv6; - out->addr.ip6.port = port; - out->addr.ip6.addr.n0 = addr[0]; - out->addr.ip6.addr.n1 = addr[1]; - out->addr.ip6.addr.n2 = addr[2]; - out->addr.ip6.addr.n3 = addr[3]; - out->addr.ip6.addr.h0 = addr[4]; - out->addr.ip6.addr.h1 = addr[5]; - out->addr.ip6.addr.h2 = addr[6]; - out->addr.ip6.addr.h3 = addr[7]; + 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]; + } } __wasi_errno_t @@ -2911,9 +2935,7 @@ wasi_ssp_sock_addr_local( __wasi_fd_t fd, __wasi_addr_t *addr) { struct fd_object *fo; - uint8 buf[16]; - __wasi_ip_port_t port; - uint8 is_ipv4; + bh_sockaddr_t bh_addr; int ret; __wasi_errno_t error = @@ -2921,19 +2943,13 @@ wasi_ssp_sock_addr_local( if (error != __WASI_ESUCCESS) return error; - ret = os_socket_addr_local(fd_number(fo), buf, sizeof(buf) / sizeof(buf[0]), - &port, &is_ipv4); + ret = os_socket_addr_local(fd_number(fo), &bh_addr); fd_object_release(fo); if (ret != BHT_OK) { return convert_errno(errno); } - if (is_ipv4) { - ipv4_addr_to_wasi_addr(*(uint32_t *)buf, port, addr); - } - else { - ipv6_addr_to_wasi_addr((uint16 *)buf, port, addr); - } + bh_sockaddr_to_wasi_addr(&bh_addr, addr); return __WASI_ESUCCESS; } @@ -2946,9 +2962,7 @@ wasi_ssp_sock_addr_remote( __wasi_fd_t fd, __wasi_addr_t *addr) { struct fd_object *fo; - uint8 buf[16]; - __wasi_ip_port_t port; - uint8 is_ipv4; + bh_sockaddr_t bh_addr; int ret; __wasi_errno_t error = @@ -2956,25 +2970,19 @@ wasi_ssp_sock_addr_remote( if (error != __WASI_ESUCCESS) return error; - ret = os_socket_addr_remote(fd_number(fo), buf, - sizeof(buf) / sizeof(buf[0]), &port, &is_ipv4); + ret = os_socket_addr_remote(fd_number(fo), &bh_addr); fd_object_release(fo); if (ret != BHT_OK) { return convert_errno(errno); } - if (is_ipv4) { - ipv4_addr_to_wasi_addr(*(uint32_t *)buf, port, addr); - } - else { - ipv6_addr_to_wasi_addr((uint16 *)buf, port, addr); - } + bh_sockaddr_to_wasi_addr(&bh_addr, addr); return __WASI_ESUCCESS; } static bool -wasi_addr_to_string(__wasi_addr_t *addr, char *buf, size_t buflen) +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"; @@ -3077,14 +3085,8 @@ wasi_ssp_sock_addr_resolve( for (size_t i = 0; i < actual_info_size; i++) { addr_info[i].type = wamr_addr_info[i].is_tcp ? SOCKET_STREAM : SOCKET_DGRAM; - if (wamr_addr_info[i].is_ipv4) { - ipv4_addr_to_wasi_addr(*(uint32_t *)wamr_addr_info[i].addr, - wamr_addr_info[i].port, &addr_info[i].addr); - } - else { - ipv6_addr_to_wasi_addr((uint16_t *)wamr_addr_info[i].addr, - wamr_addr_info[i].port, &addr_info[i].addr); - } + bh_sockaddr_to_wasi_addr(&wamr_addr_info[i].sockaddr, + &addr_info[i].addr); } wasm_runtime_free(wamr_addr_info); @@ -3202,9 +3204,24 @@ wasmtime_ssp_sock_recv( struct fd_table *curfds, #endif __wasi_fd_t sock, void *buf, size_t buf_len, size_t *recv_len) +{ + __wasi_addr_t src_addr; + + return wasmtime_ssp_sock_recv_from(curfds, sock, buf, buf_len, 0, &src_addr, + recv_len); +} + +__wasi_errno_t +wasmtime_ssp_sock_recv_from( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, void *buf, size_t buf_len, __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, size_t *recv_len) { struct fd_object *fo; __wasi_errno_t error; + bh_sockaddr_t sockaddr; int ret; error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0); @@ -3212,12 +3229,14 @@ wasmtime_ssp_sock_recv( return error; } - ret = os_socket_recv(fd_number(fo), buf, buf_len); + ret = os_socket_recv_from(fd_number(fo), buf, buf_len, 0, &sockaddr); fd_object_release(fo); if (-1 == ret) { return convert_errno(errno); } + bh_sockaddr_to_wasi_addr(&sockaddr, src_addr); + *recv_len = (size_t)ret; return __WASI_ESUCCESS; } @@ -3248,6 +3267,45 @@ wasmtime_ssp_sock_send( return __WASI_ESUCCESS; } +__wasi_errno_t +wasmtime_ssp_sock_send_to( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t sock, const void *buf, size_t buf_len, + __wasi_siflags_t si_flags, const __wasi_addr_t *dest_addr, size_t *sent_len) +{ + char addr_buf[48] = { 0 }; + struct fd_object *fo; + __wasi_errno_t error; + int ret; + bh_sockaddr_t sockaddr; + + if (!wasi_addr_to_string(dest_addr, addr_buf, sizeof(addr_buf))) { + return __WASI_EPROTONOSUPPORT; + } + + if (!addr_pool_search(addr_pool, addr_buf)) { + return __WASI_EACCES; + } + + error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) { + return error; + } + + wasi_addr_to_bh_sockaddr(dest_addr, &sockaddr); + + ret = os_socket_send_to(fd_number(fo), buf, buf_len, 0, &sockaddr); + fd_object_release(fo); + if (-1 == ret) { + return convert_errno(errno); + } + + *sent_len = (size_t)ret; + return __WASI_ESUCCESS; +} + __wasi_errno_t wasmtime_ssp_sock_shutdown( #if !defined(WASMTIME_SSP_STATIC_CURFDS) @@ -3403,7 +3461,7 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask) { struct addr_pool *cur = addr_pool; struct addr_pool *next; - bh_inet_network_output_t target; + bh_ip_addr_buffer_t target; if (!addr_pool) { return false; @@ -3464,7 +3522,7 @@ init_address_mask(uint8_t *buf, size_t buflen, size_t mask) /* target must be in network byte order */ static bool compare_address(const struct addr_pool *addr_pool_entry, - bh_inet_network_output_t *target) + bh_ip_addr_buffer_t *target) { uint8_t maskbuf[16] = { 0 }; uint8_t basebuf[16] = { 0 }; @@ -3515,7 +3573,7 @@ bool addr_pool_search(struct addr_pool *addr_pool, const char *addr) { struct addr_pool *cur = addr_pool->next; - bh_inet_network_output_t target; + bh_ip_addr_buffer_t target; __wasi_addr_type_t addr_type; if (os_socket_inet_network(true, addr, &target) != BHT_OK) { diff --git a/core/shared/platform/common/posix/posix_socket.c b/core/shared/platform/common/posix/posix_socket.c index f1effb00..229aa589 100644 --- a/core/shared/platform/common/posix/posix_socket.c +++ b/core/shared/platform/common/posix/posix_socket.c @@ -34,6 +34,77 @@ textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out) return false; } +static int +sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen, + bh_sockaddr_t *bh_sockaddr) +{ + switch (sockaddr->sa_family) { + case AF_INET: + { + struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr; + + assert(socklen >= sizeof(struct sockaddr_in)); + + bh_sockaddr->port = ntohs(addr->sin_port); + bh_sockaddr->addr_bufer.ipv4 = ntohl(addr->sin_addr.s_addr); + bh_sockaddr->is_ipv4 = true; + return BHT_OK; + } + case AF_INET6: + { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr; + size_t i; + + assert(socklen >= sizeof(struct sockaddr_in6)); + + bh_sockaddr->port = ntohs(addr->sin6_port); + + for (i = 0; i < sizeof(bh_sockaddr->addr_bufer.ipv6) + / sizeof(bh_sockaddr->addr_bufer.ipv6[0]); + i++) { + uint16 part_addr = addr->sin6_addr.s6_addr[i * 2] + | (addr->sin6_addr.s6_addr[i * 2 + 1] << 8); + bh_sockaddr->addr_bufer.ipv6[i] = ntohs(part_addr); + } + + bh_sockaddr->is_ipv4 = false; + return BHT_OK; + } + default: + errno = EAFNOSUPPORT; + return BHT_ERROR; + } +} + +static void +bh_sockaddr_to_sockaddr(const bh_sockaddr_t *bh_sockaddr, + struct sockaddr_storage *sockaddr, socklen_t *socklen) +{ + if (bh_sockaddr->is_ipv4) { + struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr; + addr->sin_port = htons(bh_sockaddr->port); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = htonl(bh_sockaddr->addr_bufer.ipv4); + *socklen = sizeof(*addr); + } + else { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr; + size_t i; + addr->sin6_port = htons(bh_sockaddr->port); + addr->sin6_family = AF_INET6; + + for (i = 0; i < sizeof(bh_sockaddr->addr_bufer.ipv6) + / sizeof(bh_sockaddr->addr_bufer.ipv6[0]); + i++) { + uint16 part_addr = htons(bh_sockaddr->addr_bufer.ipv6[i]); + addr->sin6_addr.s6_addr[i * 2] = 0xff & part_addr; + addr->sin6_addr.s6_addr[i * 2 + 1] = (0xff00 & part_addr) >> 8; + } + + *socklen = sizeof(*addr); + } +} + int os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) { @@ -168,12 +239,48 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) return recv(socket, buf, len, 0); } +int +os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, + bh_sockaddr_t *src_addr) +{ + struct sockaddr_storage sock_addr = {}; + socklen_t socklen = sizeof(sock_addr); + int ret; + + ret = recvfrom(socket, buf, len, flags, (struct sockaddr *)&sock_addr, + &socklen); + + if (ret < 0) { + return ret; + } + + if (src_addr) { + sockaddr_to_bh_sockaddr((struct sockaddr *)&sock_addr, socklen, + src_addr); + } + + return ret; +} + int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) { return send(socket, buf, len, 0); } +int +os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, + int flags, const bh_sockaddr_t *dest_addr) +{ + struct sockaddr_storage sock_addr = {}; + socklen_t socklen = 0; + + bh_sockaddr_to_sockaddr(dest_addr, &sock_addr, &socklen); + + return sendto(socket, buf, len, 0, (const struct sockaddr *)&sock_addr, + socklen); +} + int os_socket_close(bh_socket_t socket) { @@ -189,8 +296,7 @@ os_socket_shutdown(bh_socket_t socket) } int -os_socket_inet_network(bool is_ipv4, const char *cp, - bh_inet_network_output_t *out) +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) { if (!cp) return BHT_ERROR; @@ -278,26 +384,8 @@ os_socket_addr_resolve(const char *host, const char *service, continue; } - if (res->ai_family == AF_INET) { - struct sockaddr_in *addr_in = - (struct sockaddr_in *)res->ai_addr; - - addr_info[pos].port = addr_in->sin_port; - addr_info[pos].is_ipv4 = 1; - memcpy(addr_info[pos].addr, &addr_in->sin_addr, - sizeof(addr_in->sin_addr)); - } - else { - struct sockaddr_in6 *addr_in = - (struct sockaddr_in6 *)res->ai_addr; - - addr_info[pos].port = addr_in->sin6_port; - addr_info[pos].is_ipv4 = 0; - for (int i = 0; i < 8; i++) { - ((uint16 *)addr_info[pos].addr)[i] = - ntohs(((uint16_t *)&addr_in->sin6_addr)[i]); - } - } + 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; } @@ -312,45 +400,6 @@ os_socket_addr_resolve(const char *host, const char *service, return BHT_OK; } -static int -os_socket_convert_sockaddr(struct sockaddr *addr, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4) -{ - assert(buf); - assert(is_ipv4); - assert(port); - - switch (addr->sa_family) { - case AF_INET: - { - struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; - - assert(buflen >= sizeof(addr_in->sin_addr)); - *port = ntohs(addr_in->sin_port); - memcpy(buf, &addr_in->sin_addr, sizeof(addr_in->sin_addr)); - *is_ipv4 = true; - break; - } - case AF_INET6: - { - struct sockaddr_in6 *addr_in = (struct sockaddr_in6 *)addr; - assert(buflen >= sizeof(addr_in->sin6_addr)); - *port = ntohs(addr_in->sin6_port); - - for (int i = 0; i < 8; i++) { - ((uint16_t *)buf)[i] = - ntohs(((uint16_t *)&addr_in->sin6_addr)[i]); - } - *is_ipv4 = false; - break; - } - default: - return BHT_ERROR; - } - - return BHT_OK; -} - int os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) { @@ -400,8 +449,7 @@ os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) } int -os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4) +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); @@ -413,13 +461,12 @@ os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, return BHT_ERROR; } - return os_socket_convert_sockaddr((struct sockaddr *)&addr_storage, buf, - buflen, port, is_ipv4); + return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len, + sockaddr); } int -os_socket_addr_remote(bh_socket_t socket, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4) +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); @@ -431,6 +478,6 @@ os_socket_addr_remote(bh_socket_t socket, uint8_t *buf, size_t buflen, return BHT_ERROR; } - return os_socket_convert_sockaddr((struct sockaddr *)&addr_storage, buf, - buflen, port, is_ipv4); + return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len, + sockaddr); } \ No newline at end of file diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index 77de1b3f..148dc45c 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -292,6 +292,18 @@ os_sem_unlink(const char *name); * need to implement these APIs */ +typedef union { + uint32 ipv4; + uint16 ipv6[8]; + uint8 data[1]; +} bh_ip_addr_buffer_t; + +typedef struct { + bh_ip_addr_buffer_t addr_bufer; + uint16 port; + bool is_ipv4; +} bh_sockaddr_t; + /** * Create a socket * @@ -381,6 +393,22 @@ os_socket_connect(bh_socket_t socket, const char *addr, int port); int os_socket_recv(bh_socket_t socket, void *buf, unsigned int len); +/** + * Blocking receive message from a socket. + * + * @param socket the socket to send message + * @param buf the buffer to store the data + * @param len length of the buffer, this API does not guarantee that + * [len] bytes are received + * @param flags control the operation + * @param src_addr source address + * + * @return number of bytes sent if success, -1 otherwise + */ +int +os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, + bh_sockaddr_t *src_addr); + /** * Blocking send message on a socket * @@ -393,6 +421,21 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len); int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len); +/** + * Blocking send message on a socket to the target address + * + * @param socket the socket to send message + * @param buf the buffer of data to be sent + * @param len length of the buffer + * @param flags control the operation + * @param dest_addr target address + * + * @return number of bytes sent if success, -1 otherwise + */ +int +os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, + int flags, const bh_sockaddr_t *dest_addr); + /** * Close a socket * @@ -413,12 +456,6 @@ os_socket_close(bh_socket_t socket); int os_socket_shutdown(bh_socket_t socket); -typedef union { - uint32 ipv4; - uint16 ipv6[8]; - uint8_t data[0]; -} bh_inet_network_output_t; - /** * converts cp into a number in host byte order suitable for use as * an Internet network address @@ -435,13 +472,10 @@ typedef union { * If the input is invalid, -1 is returned */ int -os_socket_inet_network(bool is_ipv4, const char *cp, - bh_inet_network_output_t *out); +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out); typedef struct { - uint8_t addr[16]; - uint16_t port; - uint8_t is_ipv4; + bh_sockaddr_t sockaddr; uint8_t is_tcp; } bh_addr_info_t; @@ -478,38 +512,24 @@ os_socket_addr_resolve(const char *host, const char *service, * * @param socket the local socket * - * @param buf buffer to store the address - * - * @param buflen length of the buf buffer - * - * @param port a buffer for storing socket's port - * - * @param is_ipv4 a buffer for storing information about the address family + * @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, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4); +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 buf buffer to store the address - * - * @param buflen length of the buf buffer - * - * @param port a buffer for storing socket's port - * - * @param is_ipv4 a buffer for storing information about the address family + * @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, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4); +os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr); /** * Set the send timeout until reporting an error diff --git a/core/shared/platform/linux-sgx/sgx_socket.c b/core/shared/platform/linux-sgx/sgx_socket.c index 089d7c78..b2979592 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.c +++ b/core/shared/platform/linux-sgx/sgx_socket.c @@ -605,8 +605,7 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) } int -os_socket_inet_network(bool is_ipv4, const char *cp, - bh_inet_network_output_t *out) +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) { if (!cp) return BHT_ERROR; @@ -662,6 +661,15 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) return ret; } +int +os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, + bh_sockaddr_t *src_addr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) { @@ -678,6 +686,15 @@ os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) return ret; } +int +os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, + int flags, const bh_sockaddr_t *dest_addr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_shutdown(bh_socket_t socket) { @@ -696,8 +713,7 @@ os_socket_addr_resolve(const char *host, const char *service, } int -os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4) +os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) { errno = ENOSYS; @@ -705,8 +721,7 @@ os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, } int -os_socket_addr_remote(bh_socket_t socket, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4) +os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) { errno = ENOSYS; diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index bf031d1b..abd2f376 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -143,12 +143,30 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) return recv(socket, buf, len, 0); } +int +os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, + bh_sockaddr_t *src_addr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) { return send(socket, buf, len, 0); } +int +os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, + int flags, const bh_sockaddr_t *dest_addr) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_close(bh_socket_t socket) { @@ -164,8 +182,7 @@ os_socket_shutdown(bh_socket_t socket) } int -os_socket_inet_network(bool is_ipv4, const char *cp, - bh_inet_network_output_t *out) +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) { if (!cp) return BHT_ERROR; @@ -201,8 +218,7 @@ os_socket_addr_resolve(const char *host, const char *service, } int -os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4) +os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) { errno = ENOSYS; @@ -242,8 +258,7 @@ os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) } int -os_socket_addr_remote(bh_socket_t socket, uint8_t *buf, size_t buflen, - uint16_t *port, uint8_t *is_ipv4) +os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) { errno = ENOSYS; diff --git a/samples/socket-api/CMakeLists.txt b/samples/socket-api/CMakeLists.txt index c8bd74a0..25385b29 100644 --- a/samples/socket-api/CMakeLists.txt +++ b/samples/socket-api/CMakeLists.txt @@ -105,6 +105,10 @@ 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 ############################################ diff --git a/samples/socket-api/wasm-src/CMakeLists.txt b/samples/socket-api/wasm-src/CMakeLists.txt index 9dbcaa63..32cd7276 100644 --- a/samples/socket-api/wasm-src/CMakeLists.txt +++ b/samples/socket-api/wasm-src/CMakeLists.txt @@ -81,3 +81,5 @@ compile_with_clang(tcp_client.c) compile_with_clang(send_recv.c) compile_with_clang(addr_resolve.c) compile_with_clang(socket_opts.c) +compile_with_clang(udp_client.c) +compile_with_clang(udp_server.c) diff --git a/samples/socket-api/wasm-src/tcp_utils.h b/samples/socket-api/wasm-src/socket_utils.h similarity index 100% rename from samples/socket-api/wasm-src/tcp_utils.h rename to samples/socket-api/wasm-src/socket_utils.h diff --git a/samples/socket-api/wasm-src/tcp_client.c b/samples/socket-api/wasm-src/tcp_client.c index 06892070..937d70e5 100644 --- a/samples/socket-api/wasm-src/tcp_client.c +++ b/samples/socket-api/wasm-src/tcp_client.c @@ -2,7 +2,7 @@ * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#include "tcp_utils.h" +#include "socket_utils.h" #include #include diff --git a/samples/socket-api/wasm-src/tcp_server.c b/samples/socket-api/wasm-src/tcp_server.c index c0096c45..7977b9c5 100644 --- a/samples/socket-api/wasm-src/tcp_server.c +++ b/samples/socket-api/wasm-src/tcp_server.c @@ -2,7 +2,7 @@ * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#include "tcp_utils.h" +#include "socket_utils.h" #include #include diff --git a/samples/socket-api/wasm-src/udp_client.c b/samples/socket-api/wasm-src/udp_client.c new file mode 100644 index 00000000..96d9a2b8 --- /dev/null +++ b/samples/socket-api/wasm-src/udp_client.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#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; +} diff --git a/samples/socket-api/wasm-src/udp_server.c b/samples/socket-api/wasm-src/udp_server.c new file mode 100644 index 00000000..02b14500 --- /dev/null +++ b/samples/socket-api/wasm-src/udp_server.c @@ -0,0 +1,118 @@ +/* + * 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 +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#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; + init_sockaddr_inet6((struct sockaddr_in6 *)&addr); + } + else { + af = AF_INET; + 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"); + addrlen = sizeof(addr); + 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) { + 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; +}