From 3e77b053c366781310f4612319837a70490e8d2d Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Mon, 1 Aug 2022 09:15:33 +0200 Subject: [PATCH] Enhance sock_addr_local syscall (#1320) Slightly change the __wasi_sock_addr_local interface - since we already have a `__wasi_addr_t` structure which is an union, there's no need for passing the length around - the address buffer will always have the right length (i.e. max of all address families). --- .../lib-socket/inc/wasi_socket_ext.h | 10 +-- .../lib-socket/src/wasi/wasi_socket_ext.c | 72 ++++++++++++------- .../libraries/libc-wasi/libc_wasi_wrapper.c | 11 +-- .../include/wasmtime_ssp.h | 2 +- .../sandboxed-system-primitives/src/posix.c | 32 +++++++-- .../platform/common/posix/posix_socket.c | 49 +++++++++++++ .../platform/include/platform_api_extension.h | 19 +++++ core/shared/platform/linux-sgx/sgx_socket.c | 11 ++- core/shared/platform/linux-sgx/sgx_socket.h | 3 + core/shared/platform/windows/win_socket.c | 9 +++ samples/socket-api/wasm-src/tcp_client.c | 17 +++++ 11 files changed, 195 insertions(+), 40 deletions(-) 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 e89837bc..b76b669e 100644 --- a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h +++ b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h @@ -114,6 +114,9 @@ sendmsg(int sockfd, const struct msghdr *msg, int flags); int socket(int domain, int type, int protocol); + +int +getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); #endif /** @@ -141,16 +144,15 @@ __wasi_sock_accept(__wasi_fd_t fd, __wasi_fd_t *fd_new) * either IP4 or IP6. */ int32_t -__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1, - int32_t arg2) +__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1) __attribute__((__import_module__("wasi_snapshot_preview1"), __import_name__("sock_addr_local"))); static inline __wasi_errno_t -__wasi_sock_addr_local(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len) +__wasi_sock_addr_local(__wasi_fd_t fd, __wasi_addr_t *addr) { return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_local( - (int32_t)fd, (int32_t)buf, (int32_t)buf_len); + (int32_t)fd, (int32_t)addr); } /** 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 a81ff6ce..d90d8626 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 @@ -54,6 +54,38 @@ sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen, return ret; } +static __wasi_errno_t +wasi_addr_to_sockaddr(const __wasi_addr_t *wasi_addr, + struct sockaddr *sock_addr, socklen_t *addrlen) +{ + switch (wasi_addr->kind) { + case IPv4: + { + struct sockaddr_in sock_addr_in = { 0 }; + uint32_t s_addr; + + s_addr = (wasi_addr.addr.ip4.addr.n0 << 24) + | (wasi_addr.addr.ip4.addr.n1 << 16) + | (wasi_addr.addr.ip4.addr.n2 << 8) + | wasi_addr.addr.ip4.addr.n3; + + sock_addr_in.sin_family = AF_INET; + sock_addr_in.sin_addr.s_addr = htonl(s_addr); + sock_addr_in.sin_port = htons(wasi_addr->addr.ip4.port); + memcpy(sock_addr, &sock_addr_in, sizeof(sock_addr_in)); + + *addrlen = sizeof(sock_addr_in); + break; + } + case IPv6: + // TODO: IPV6 + return __WASI_ERRNO_AFNOSUPPORT; + default: + return __WASI_ERRNO_AFNOSUPPORT; + } + return __WASI_ERRNO_SUCCESS; +} + static __wasi_errno_t sock_addr_remote(__wasi_fd_t fd, struct sockaddr *sock_addr, socklen_t *addrlen) { @@ -67,30 +99,7 @@ sock_addr_remote(__wasi_fd_t fd, struct sockaddr *sock_addr, socklen_t *addrlen) return error; } - if (IPv4 == wasi_addr.kind) { - struct sockaddr_in sock_addr_in = { 0 }; - - s_addr = (wasi_addr.addr.ip4.addr.n0 << 24) - | (wasi_addr.addr.ip4.addr.n1 << 16) - | (wasi_addr.addr.ip4.addr.n2 << 8) - | wasi_addr.addr.ip4.addr.n3; - - sock_addr_in.sin_family = AF_INET; - sock_addr_in.sin_addr.s_addr = htonl(s_addr); - sock_addr_in.sin_port = htons(wasi_addr.addr.ip4.port); - memcpy(sock_addr, &sock_addr_in, sizeof(sock_addr_in)); - - *addrlen = sizeof(sock_addr_in); - } - else if (IPv6 == wasi_addr.kind) { - // TODO: IPV6 - return __WASI_ERRNO_AFNOSUPPORT; - } - else { - return __WASI_ERRNO_AFNOSUPPORT; - } - - return __WASI_ERRNO_SUCCESS; + return wasi_addr_to_sockaddr(&wasi_addr, sock_addr, addrlen); } int @@ -260,3 +269,18 @@ socket(int domain, int type, int protocol) return sockfd; } + +int +getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + __wasi_addr_t wasi_addr = { 0 }; + __wasi_errno_t error; + + error = __wasi_sock_addr_local(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + error = wasi_addr_to_sockaddr(&wasi_addr, addr, addrlen); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index b4e081df..77285c27 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -1009,8 +1009,8 @@ wasi_sock_accept(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_fd_t *fd_new) } static wasi_errno_t -wasi_sock_addr_local(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *buf, - wasi_size_t buf_len) +wasi_sock_addr_local(wasm_exec_env_t exec_env, wasi_fd_t fd, + __wasi_addr_t *addr) { wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); @@ -1019,9 +1019,12 @@ wasi_sock_addr_local(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *buf, if (!wasi_ctx) return __WASI_EACCES; + if (!validate_native_addr(addr, sizeof(__wasi_addr_t))) + return __WASI_EINVAL; + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - return wasi_ssp_sock_addr_local(curfds, fd, buf, buf_len); + return wasi_ssp_sock_addr_local(curfds, fd, addr); } static wasi_errno_t @@ -1401,7 +1404,7 @@ static NativeSymbol native_symbols_libc_wasi[] = { REG_NATIVE_FUNC(proc_raise, "(i)i"), REG_NATIVE_FUNC(random_get, "(*~)i"), REG_NATIVE_FUNC(sock_accept, "(i*)i"), - REG_NATIVE_FUNC(sock_addr_local, "(i*i)i"), + REG_NATIVE_FUNC(sock_addr_local, "(i*)i"), REG_NATIVE_FUNC(sock_addr_remote, "(i*i)i"), REG_NATIVE_FUNC(sock_addr_resolve, "($$**i*)i"), REG_NATIVE_FUNC(sock_bind, "(i*)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 2a164ee3..7bb40654 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 @@ -1007,7 +1007,7 @@ wasi_ssp_sock_addr_local( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len + __wasi_fd_t fd, __wasi_addr_t *addr ) __attribute__((__warn_unused_result__)); __wasi_errno_t 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 cd7c6546..19d7d2b8 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 @@ -203,12 +203,14 @@ convert_clockid(__wasi_clockid_t in, clockid_t *out) static void ipv4_addr_to_wasi_addr(uint32_t addr, __wasi_ip_port_t port, __wasi_addr_t *out) { + addr = ntohl(addr); + out->kind = IPv4; out->addr.ip4.port = port; - out->addr.ip4.addr.n3 = (addr & 0xFF000000) >> 24; - out->addr.ip4.addr.n2 = (addr & 0x00FF0000) >> 16; - out->addr.ip4.addr.n1 = (addr & 0x0000FF00) >> 8; - out->addr.ip4.addr.n0 = (addr & 0x000000FF); + 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); } // Converts an IPv6 binary address object to WASI address object. @@ -2881,16 +2883,34 @@ wasi_ssp_sock_addr_local( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, #endif - __wasi_fd_t fd, uint8 *buf, __wasi_size_t buf_len) + __wasi_fd_t fd, __wasi_addr_t *addr) { struct fd_object *fo; + uint8 buf[16]; + __wasi_ip_port_t port; + uint8 is_ipv4; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0); if (error != __WASI_ESUCCESS) return error; + ret = os_socket_addr_local(fd_number(fo), buf, sizeof(buf) / sizeof(buf[0]), + &port, &is_ipv4); fd_object_release(fo); - return __WASI_ENOSYS; + 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); + } + + return __WASI_ESUCCESS; } __wasi_errno_t diff --git a/core/shared/platform/common/posix/posix_socket.c b/core/shared/platform/common/posix/posix_socket.c index be9ede0a..a2c1b0f1 100644 --- a/core/shared/platform/common/posix/posix_socket.c +++ b/core/shared/platform/common/posix/posix_socket.c @@ -270,5 +270,54 @@ os_socket_addr_resolve(const char *host, const char *service, *max_info_size = pos; freeaddrinfo(result); + return BHT_OK; +} + +int +os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, + uint16_t *port, uint8_t *is_ipv4) +{ + struct sockaddr_storage addr_storage = { 0 }; + socklen_t addr_len = sizeof(addr_storage); + int ret; + + assert(buf); + assert(is_ipv4); + assert(port); + + ret = getsockname(socket, (struct sockaddr *)&addr_storage, &addr_len); + + if (ret != BHT_OK) { + return BHT_ERROR; + } + + switch (addr_storage.ss_family) { + case AF_INET: + { + struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr_storage; + + 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_storage; + 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; } \ 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 08bf75b3..b6e97406 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -374,6 +374,25 @@ os_socket_addr_resolve(const char *host, const char *service, 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 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 + * + * @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); + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/linux-sgx/sgx_socket.c b/core/shared/platform/linux-sgx/sgx_socket.c index fb26c905..b7dc5d01 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.c +++ b/core/shared/platform/linux-sgx/sgx_socket.c @@ -105,7 +105,7 @@ htonl(uint32 value) return value; } -static uint32 +uint32 ntohl(uint32 value) { return htonl(value); @@ -632,4 +632,13 @@ os_socket_addr_resolve(const char *host, const char *service, return BHT_ERROR; } +int +os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, + uint16_t *port, uint8_t *is_ipv4) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + #endif diff --git a/core/shared/platform/linux-sgx/sgx_socket.h b/core/shared/platform/linux-sgx/sgx_socket.h index 7dc05fce..19e2b8cd 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.h +++ b/core/shared/platform/linux-sgx/sgx_socket.h @@ -95,6 +95,9 @@ struct sockaddr { char sa_data[14]; /* Address data. */ }; +uint32_t +ntohl(uint32_t value); + int socket(int domain, int type, int protocol); diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index 5e60c3ac..c023593f 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -171,5 +171,14 @@ os_socket_addr_resolve(const char *host, const char *service, { errno = ENOSYS; + return BHT_ERROR; +} + +int +os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, + uint16_t *port, uint8_t *is_ipv4) +{ + errno = ENOSYS; + return BHT_ERROR; } \ No newline at end of file diff --git a/samples/socket-api/wasm-src/tcp_client.c b/samples/socket-api/wasm-src/tcp_client.c index 4fcf8707..e4a7ea34 100644 --- a/samples/socket-api/wasm-src/tcp_client.c +++ b/samples/socket-api/wasm-src/tcp_client.c @@ -19,7 +19,10 @@ main(int argc, char *argv[]) { int socket_fd, ret, total_size = 0; char buffer[1024] = { 0 }; + char ip_string[16] = { 0 }; struct sockaddr_in server_address = { 0 }; + struct sockaddr_in local_address = { 0 }; + socklen_t len; printf("[Client] Create socket\n"); socket_fd = socket(AF_INET, SOCK_STREAM, 0); @@ -42,6 +45,20 @@ main(int argc, char *argv[]) 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; + } + + inet_ntop(AF_INET, &local_address.sin_addr, ip_string, + sizeof(ip_string) / sizeof(ip_string[0])); + + printf("[Client] Local address is: %s:%d\n", ip_string, + ntohs(local_address.sin_port)); + printf("[Client] Client receive\n"); while (1) { ret = recv(socket_fd, buffer + total_size, sizeof(buffer) - total_size,