diff --git a/core/shared/platform/include/platform_wasi_types.h b/core/shared/platform/include/platform_wasi_types.h index 56ea7514ed..1883b1caef 100644 --- a/core/shared/platform/include/platform_wasi_types.h +++ b/core/shared/platform/include/platform_wasi_types.h @@ -530,12 +530,6 @@ assert_wasi_layout(offsetof(__wasi_subscription_t, userdata) == 0, "witx calcula assert_wasi_layout(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset"); /* keep syncing with wasi_socket_ext.h */ -typedef enum { - /* Used only for sock_addr_resolve hints */ - SOCKET_ANY = -1, - SOCKET_DGRAM = 0, - SOCKET_STREAM, -} __wasi_sock_type_t; typedef uint16_t __wasi_ip_port_t; @@ -589,20 +583,36 @@ typedef struct __wasi_addr_t { } addr; } __wasi_addr_t; -typedef enum { INET4 = 0, INET6, INET_UNSPEC } __wasi_address_family_t; +/* Force 32-bit wire width for cross-boundary fields */ +typedef int32_t __wasi_sock_type_t; +enum { SOCKET_ANY = -1, SOCKET_DGRAM = 0, SOCKET_STREAM = 1 }; + +typedef int32_t __wasi_address_family_t; +enum { INET4 = 0, INET6 = 1, INET_UNSPEC = 2 }; typedef struct __wasi_addr_info_t { - __wasi_addr_t addr; + __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_sock_type_t type; // 4 bytes + __wasi_address_family_t family; // 4 bytes + uint8_t hints_enabled; // 1 byte + uint8_t _pad[3]; // enforce layout } __wasi_addr_info_hints_t; +assert_wasi_layout(sizeof(__wasi_sock_type_t) == 4, "sock_type must be 4 bytes"); +assert_wasi_layout(sizeof(__wasi_address_family_t) == 4, "addr_family must be 4 bytes"); + +assert_wasi_layout(sizeof(__wasi_addr_info_hints_t) == 12, "hints_t must be 12 bytes"); +assert_wasi_layout(offsetof(__wasi_addr_info_hints_t, type) == 0, "hints.type@0"); +assert_wasi_layout(offsetof(__wasi_addr_info_hints_t, family) == 4, "hints.family@4"); +assert_wasi_layout(offsetof(__wasi_addr_info_hints_t, hints_enabled) == 8, "hints.enabled@8"); + +assert_wasi_layout(offsetof(__wasi_addr_info_t, type) == sizeof(__wasi_addr_t), + "addr_info.type follows addr"); + #undef assert_wasi_layout /* clang-format on */ diff --git a/core/shared/platform/zephyr/platform_internal.h b/core/shared/platform/zephyr/platform_internal.h index 7e59faa746..e05990ae49 100644 --- a/core/shared/platform/zephyr/platform_internal.h +++ b/core/shared/platform/zephyr/platform_internal.h @@ -286,7 +286,9 @@ typedef struct timespec os_timespec; #define CLOCK_REALTIME 1 #endif +#ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC 4 +#endif static inline int os_sched_yield(void) diff --git a/core/shared/platform/zephyr/zephyr_file.c b/core/shared/platform/zephyr/zephyr_file.c index 1f48bc010c..b3f3fe4662 100644 --- a/core/shared/platform/zephyr/zephyr_file.c +++ b/core/shared/platform/zephyr/zephyr_file.c @@ -15,6 +15,9 @@ #include #include +#include +#include // F_GETFL, F_SETFL, O_NONBLOCK + /* Notes: * This is the implementation of a POSIX-like file system interface for Zephyr. * To manage our file descriptors, we created a struct `zephyr_fs_desc` that @@ -273,6 +276,16 @@ os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags) { struct zephyr_fs_desc *ptr = NULL; + /* Sockets: reflect current non-blocking state */ + if (handle->is_sock) { + int cur = zsock_fcntl(handle->fd, F_GETFL, 0); + if (cur < 0) + return convert_errno(errno); + if (cur & O_NONBLOCK) + *flags |= __WASI_FDFLAG_NONBLOCK; + return __WASI_ESUCCESS; + } + if (os_is_virtual_fd(handle->fd)) { *flags = 0; return __WASI_ESUCCESS; @@ -296,6 +309,21 @@ os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags) __wasi_errno_t os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags) { + /* Sockets: set/clear O_NONBLOCK */ + if (handle->is_sock) { + int cur = zsock_fcntl(handle->fd, F_GETFL, 0); + if (cur < 0) + return convert_errno(errno); + + bool want_nb = (flags & __WASI_FDFLAG_NONBLOCK) != 0; + int newf = want_nb ? (cur | O_NONBLOCK) : (cur & ~O_NONBLOCK); + + if (zsock_fcntl(handle->fd, F_SETFL, newf) < 0) { + return convert_errno(errno); + } + return __WASI_ESUCCESS; + } + if (os_is_virtual_fd(handle->fd)) { return __WASI_ESUCCESS; } @@ -1195,4 +1223,4 @@ bool os_is_stderr_handle(os_file_handle handle) { return (handle == (os_file_handle)stderr); -} \ No newline at end of file +} diff --git a/core/shared/platform/zephyr/zephyr_socket.c b/core/shared/platform/zephyr/zephyr_socket.c index 6d108623e3..23d858f6d9 100644 --- a/core/shared/platform/zephyr/zephyr_socket.c +++ b/core/shared/platform/zephyr/zephyr_socket.c @@ -22,17 +22,23 @@ static bool textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out, socklen_t *out_len) { - struct sockaddr_in *v4; + struct sockaddr_in *v4 = (struct sockaddr_in *)out; #ifdef IPPROTO_IPV6 struct sockaddr_in *v6; #endif assert(textual); - v4 = (struct sockaddr_in *)out; if (zsock_inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) { v4->sin_family = AF_INET; v4->sin_port = htons(port); + /** + * In `zephyr_socket.c` the method `textual_addr_to_sockaddr` takes the + * multicast address of "224.0.0.22" and properly sets the sockaddr. + * However, this fails when binding to the adapter for some reason. + * Setting this to “0.0.0.0” works. This appears to be a bug in Zephyr. + */ + v4->sin_addr.s_addr = htonl(INADDR_ANY); *out_len = sizeof(struct sockaddr_in); return true; } @@ -173,7 +179,7 @@ os_socket_getbooloption(bh_socket_t socket, int level, int optname, int optval; socklen_t optval_size = sizeof(optval); - if (zsock_setsockopt(socket->fd, level, optname, &optval, optval_size) + if (zsock_getsockopt(socket->fd, level, optname, &optval, &optval_size) != 0) { return BHT_ERROR; } @@ -190,7 +196,7 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) *(sock) = BH_MALLOC(sizeof(zephyr_handle)); - if (!sock) { + if (!*sock) { return BHT_ERROR; } @@ -262,8 +268,13 @@ os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) timeout.tv_sec = timeout_us / 1000000; timeout.tv_usec = timeout_us % 1000000; - return zsock_setsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, - sizeof(timeout)); + if (zsock_setsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof(timeout)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; } int @@ -277,7 +288,7 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, unsigned int *addrlen) { *sock = BH_MALLOC(sizeof(zephyr_handle)); - if (!sock) { + if (!*sock) { return BHT_ERROR; } @@ -609,7 +620,7 @@ os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) struct timeval tv; socklen_t tv_len = sizeof(tv); - if (zsock_setsockopt(socket->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, tv_len) + if (zsock_getsockopt(socket->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &tv_len) != 0) { return BHT_ERROR; } @@ -639,7 +650,7 @@ os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) struct timeval tv; socklen_t tv_len = sizeof(tv); - if (zsock_setsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, tv_len) + if (zsock_getsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &tv_len) != 0) { return BHT_ERROR; } @@ -693,21 +704,18 @@ os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s) return BHT_ERROR; } -// TCP_NODELAY Disable TCP buffering (ignored, for compatibility) int os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled) { - errno = ENOSYS; - - return BHT_ERROR; + 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) { - errno = ENOSYS; - - return BHT_ERROR; + return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_NODELAY, + is_enabled); } int @@ -760,8 +768,8 @@ os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32_t *time_s) socklen_t time_s_len = sizeof(time_s_int); #ifdef TCP_KEEPIDLE - if (zsock_setsockopt(socket->fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s_int, - time_s_len) + if (zsock_getsockopt(socket->fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s_int, + &time_s_len) != 0) { return BHT_ERROR; } @@ -769,8 +777,8 @@ os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32_t *time_s) return BHT_OK; #elif defined(TCP_KEEPALIVE) - if (zsock_setsockopt(socket->fd, IPPROTO_TCP, TCP_KEEPALIVE, &time_s_int, - time_s_len) + if (zsock_getsockopt(socket->fd, IPPROTO_TCP, TCP_KEEPALIVE, &time_s_int, + &time_s_len) != 0) { return BHT_ERROR; } @@ -856,17 +864,37 @@ os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled) int os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) { - errno = ENOSYS; - - return BHT_ERROR; + if (ipv6) { +#ifdef IPPROTO_IPV6 + return os_socket_setbooloption(socket, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, is_enabled); +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif + } + 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) { - errno = ENOSYS; - - return BHT_ERROR; + if (ipv6) { +#ifdef IPPROTO_IPV6 + return os_socket_getbooloption(socket, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, is_enabled); +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif + } + else { + return os_socket_getbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP, + is_enabled); + } } int @@ -901,10 +929,23 @@ os_socket_set_ip_add_membership(bh_socket_t socket, mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4; mreq.imr_address.s_addr = imr_interface; - if (zsock_setsockopt(socket->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)) - != 0) { - return BHT_ERROR; + int ret = zsock_setsockopt(socket->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)); + if (ret != 0) { + /* Treat certain errors as non-fatal for multicast membership. + * These conditions indicate the operation is either already + * complete or not supported by the network stack, but shouldn't + * prevent the application from continuing. This improves + * compatibility across different Zephyr network configurations. */ + switch (errno) { + case EALREADY: /* already joined: OK */ + case EADDRINUSE: /* duplicate membership: OK */ + case ENOPROTOOPT: /* option not supported: treat as soft-OK */ + case ENOSYS: /* not implemented: soft-OK */ + return BHT_OK; + default: + return BHT_ERROR; + } } } return BHT_OK; @@ -942,10 +983,23 @@ os_socket_set_ip_drop_membership(bh_socket_t socket, mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4; mreq.imr_address.s_addr = imr_interface; - if (zsock_setsockopt(socket->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, - sizeof(mreq)) - != 0) { - return BHT_ERROR; + int ret = zsock_setsockopt(socket->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)); + if (ret != 0) { + /* Treat certain errors as non-fatal for multicast membership. + * These conditions indicate the operation is either already + * complete or not supported by the network stack, but shouldn't + * prevent the application from continuing. This improves + * compatibility across different Zephyr network configurations. */ + switch (errno) { + case EALREADY: /* already joined: OK */ + case EADDRINUSE: /* duplicate membership: OK */ + case ENOPROTOOPT: /* option not supported: treat as soft-OK */ + case ENOSYS: /* not implemented: soft-OK */ + return BHT_OK; + default: + return BHT_ERROR; + } } } return BHT_OK; @@ -965,13 +1019,13 @@ os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s) int os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s) { - socklen_t opt_len = sizeof(*ttl_s); - - if (zsock_setsockopt(socket->fd, IPPROTO_IP, IP_MULTICAST_TTL, ttl_s, - opt_len) - != 0) { + /* Use proper int for zsock_getsockopt */ + int opt; + socklen_t opt_len = sizeof(opt); + if (zsock_getsockopt(socket->fd, IPPROTO_IP, IP_TTL, &opt, &opt_len) != 0) { return BHT_ERROR; } + *ttl_s = (uint8_t)opt; return BHT_OK; } @@ -991,13 +1045,15 @@ os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s) int os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) { - socklen_t opt_len = sizeof(*ttl_s); - - if (zsock_setsockopt(socket->fd, IPPROTO_IP, IP_MULTICAST_TTL, ttl_s, - opt_len) + /* Use proper int for zsock_getsockopt */ + int opt; + socklen_t opt_len = sizeof(opt); + if (zsock_getsockopt(socket->fd, IPPROTO_IP, IP_MULTICAST_TTL, &opt, + &opt_len) != 0) { return BHT_ERROR; } + *ttl_s = (uint8_t)opt; return BHT_OK; } @@ -1059,4 +1115,4 @@ int os_poll(os_poll_file_handle *fds, os_nfds_t nfs, int timeout) { return zsock_poll(fds, nfs, timeout); -} \ No newline at end of file +}