From e1bcab4afe9a92272b6df2ec7dc51b51e6ccb672 Mon Sep 17 00:00:00 2001 From: Dan Kouba Date: Wed, 27 Aug 2025 22:45:52 -0700 Subject: [PATCH 1/6] Avoid redefinition warnings for CLOCK_MONOTONIC (#1) Signed-off-by: Dan Kouba --- core/shared/platform/zephyr/platform_internal.h | 2 ++ 1 file changed, 2 insertions(+) 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) From be70c23aad8405b53bebb2293fecc50dd280c749 Mon Sep 17 00:00:00 2001 From: Dan Kouba Date: Tue, 14 Oct 2025 15:58:21 -0700 Subject: [PATCH 2/6] Allow resolution of hostname "localhost" Signed-off-by: Dan Kouba --- core/shared/platform/zephyr/zephyr_socket.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/shared/platform/zephyr/zephyr_socket.c b/core/shared/platform/zephyr/zephyr_socket.c index 6d108623e3..8a32bdbdc6 100644 --- a/core/shared/platform/zephyr/zephyr_socket.c +++ b/core/shared/platform/zephyr/zephyr_socket.c @@ -442,7 +442,16 @@ os_socket_addr_resolve(const char *host, const char *service, } } - ret = zsock_getaddrinfo(host, strlen(service) == 0 ? NULL : service, + char *_host; + if (!strcmp(host, "localhost")) { + printk("os_socket_addr_resolve called with host=\"localhost\" - " + "substituting 127.0.0.1\n"); + _host = "127.0.0.1"; + } else { + _host = (char *)host; + } + + ret = zsock_getaddrinfo(_host, strlen(service) == 0 ? NULL : service, hints_enabled ? &hints : NULL, &result); if (ret != BHT_OK) { errno = getaddrinfo_error_to_errno(ret); From 7208703cf2a6df96811f6b91856c68ecaf25530d Mon Sep 17 00:00:00 2001 From: Dan Kouba Date: Tue, 14 Oct 2025 16:02:43 -0700 Subject: [PATCH 3/6] Support get/set for flags on socket fds Signed-off-by: Dan Kouba --- core/shared/platform/zephyr/zephyr_file.c | 47 ++++++++++++++++------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/core/shared/platform/zephyr/zephyr_file.c b/core/shared/platform/zephyr/zephyr_file.c index 1f48bc010c..8c46d90a8b 100644 --- a/core/shared/platform/zephyr/zephyr_file.c +++ b/core/shared/platform/zephyr/zephyr_file.c @@ -15,6 +15,10 @@ #include #include +#include +#include // F_GETFL, F_SETFL, O_NONBLOCK +// #include + /* 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 +277,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; @@ -283,31 +297,38 @@ os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags) if ((ptr->file.flags & FS_O_APPEND) != 0) { *flags |= __WASI_FDFLAG_APPEND; } - /* Others flags: - * - __WASI_FDFLAG_DSYNC - * - __WASI_FDFLAG_RSYNC - * - __WASI_FDFLAG_SYNC - * - __WASI_FDFLAG_NONBLOCK - * Have no equivalent in Zephyr. - */ + return __WASI_ESUCCESS; } __wasi_errno_t os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags) { - if (os_is_virtual_fd(handle->fd)) { + /* 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; } - struct zephyr_fs_desc *ptr = NULL; + /* Virtual stdio */ + if (os_is_virtual_fd(handle->fd)) + return __WASI_ESUCCESS; + /* Regular files: keep existing behavior */ + struct zephyr_fs_desc *ptr = NULL; GET_FILE_SYSTEM_DESCRIPTOR(handle->fd, ptr); - - if ((flags & __WASI_FDFLAG_APPEND) != 0) { + if ((flags & __WASI_FDFLAG_APPEND) != 0) ptr->file.flags |= FS_O_APPEND; - } - /* Same as above */ + return __WASI_ESUCCESS; } From d92e4b130fb7c55a33586494517fb158fd75e282 Mon Sep 17 00:00:00 2001 From: Dan Kouba Date: Mon, 20 Oct 2025 11:53:21 -0700 Subject: [PATCH 4/6] Changes to support open62541 client/server Signed-off-by: Dan Kouba --- core/shared/platform/zephyr/zephyr_socket.c | 170 ++++++++++++-------- 1 file changed, 104 insertions(+), 66 deletions(-) diff --git a/core/shared/platform/zephyr/zephyr_socket.c b/core/shared/platform/zephyr/zephyr_socket.c index 8a32bdbdc6..c19a2e5ae1 100644 --- a/core/shared/platform/zephyr/zephyr_socket.c +++ b/core/shared/platform/zephyr/zephyr_socket.c @@ -22,15 +22,22 @@ static bool textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out, socklen_t *out_len) { + struct sockaddr_in *v4; #ifdef IPPROTO_IPV6 - struct sockaddr_in *v6; + struct sockaddr_in6 *v6; #endif assert(textual); + const char *t = textual; + + /* Normalize localhost */ + if (strcmp(t, "localhost") == 0) { + t = "127.0.0.1"; // Only IPV4 for now + } v4 = (struct sockaddr_in *)out; - if (zsock_inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) { + if (zsock_inet_pton(AF_INET, t, &v4->sin_addr.s_addr) == 1) { v4->sin_family = AF_INET; v4->sin_port = htons(port); *out_len = sizeof(struct sockaddr_in); @@ -38,11 +45,11 @@ textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out, } #ifdef IPPROTO_IPV6 - v6 = (struct sockaddr_in *)out; - if (zsock_inet_pton(AF_INET6, textual, &v6->sin6_addr.s6_addr) == 1) { + v6 = (struct sockaddr_in6 *)out; + if (zsock_inet_pton(AF_INET6, t, &v6->sin6_addr) == 1) { v6->sin6_family = AF_INET6; v6->sin6_port = htons(port); - *out_len = sizeof(struct sockaddr_in); + *out_len = sizeof(struct sockaddr_in6); return true; } #endif @@ -67,7 +74,7 @@ sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, #ifdef IPPROTO_IPV6 case AF_INET6: { - struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr; + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr; size_t i; bh_sockaddr->port = ntohs(addr->sin6_port); @@ -173,7 +180,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 +197,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; } @@ -215,40 +222,55 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) int os_socket_bind(bh_socket_t socket, const char *host, int *port) { - struct sockaddr_storage addr = { 0 }; - socklen_t socklen; - int ret; + (void)host; /* PoC: ignore host, listen on all interfaces */ - assert(host); + assert(socket); assert(port); - if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr, - &socklen)) { - return BHT_ERROR; + int ret; + int fam = AF_INET; /* default to IPv4 */ + socklen_t flen = sizeof(fam); + + /* Honor the socket's domain if available so IPv6 sockets get :: */ + (void)zsock_getsockopt(socket->fd, SOL_SOCKET, SO_DOMAIN, &fam, &flen); + +#ifdef CONFIG_NET_IPV6 + if (fam == AF_INET6) { + struct sockaddr_in6 sa6; + memset(&sa6, 0, sizeof(sa6)); + sa6.sin6_family = AF_INET6; + sa6.sin6_port = htons(*port); /* *port may be 0 */ + /* :: (all zeros) means in6addr_any */ + ret = zsock_bind(socket->fd, (struct sockaddr *)&sa6, sizeof(sa6)); + } else +#endif + { + struct sockaddr_in sa4; + memset(&sa4, 0, sizeof(sa4)); + sa4.sin_family = AF_INET; + sa4.sin_port = htons(*port); /* *port may be 0 */ + sa4.sin_addr.s_addr = htonl(INADDR_ANY); /* 0.0.0.0 */ + ret = zsock_bind(socket->fd, (struct sockaddr *)&sa4, sizeof(sa4)); } - // F_SETF_SETFD and FD_CLOEXEC are not defined in zephyr. - // SO_LINGER: Socket lingers on close (ignored, for compatibility) - - ret = zsock_bind(socket->fd, (struct sockaddr *)&addr, socklen); if (ret < 0) { - return BHT_ERROR; - } - - socklen = sizeof(addr); - if (zsock_getsockname(socket->fd, (void *)&addr, &socklen) == -1) { - return BHT_ERROR; + return BHT_ERROR; /* or convert_errno(errno) if your code uses it */ } - if (addr.ss_family == AF_INET) { // addr.sin_family - *port = ntohs(((struct sockaddr_in *)&addr)->sin_port); - } - else { -#ifdef IPPROTO_IPV6 - *port = ntohs(((struct sockaddr_in *)&addr)->sin6_port); -#else - return BHT_ERROR; + /* If caller asked for port 0, report the kernel-chosen port back */ + if (*port == 0) { + struct sockaddr_storage ss; + socklen_t sl = sizeof(ss); + if (zsock_getsockname(socket->fd, (struct sockaddr *)&ss, &sl) == 0) { + if (ss.ss_family == AF_INET) { + *port = ntohs(((struct sockaddr_in *)&ss)->sin_port); + } +#ifdef CONFIG_NET_IPV6 + else if (ss.ss_family == AF_INET6) { + *port = ntohs(((struct sockaddr_in6 *)&ss)->sin6_port); + } #endif + } } return BHT_OK; @@ -263,7 +285,7 @@ os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) timeout.tv_usec = timeout_us % 1000000; return zsock_setsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, - sizeof(timeout)); + sizeof(timeout)) == 0 ? BHT_OK : BHT_ERROR; } int @@ -277,7 +299,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; } @@ -442,18 +464,17 @@ os_socket_addr_resolve(const char *host, const char *service, } } - char *_host; - if (!strcmp(host, "localhost")) { + const char *_host = host ? host : NULL; + if (_host && strcmp(_host, "localhost") == 0) { printk("os_socket_addr_resolve called with host=\"localhost\" - " "substituting 127.0.0.1\n"); _host = "127.0.0.1"; - } else { - _host = (char *)host; } - ret = zsock_getaddrinfo(_host, strlen(service) == 0 ? NULL : service, + const char *_service = (service && service[0]) ? service : NULL; + ret = zsock_getaddrinfo(_host, _service, hints_enabled ? &hints : NULL, &result); - if (ret != BHT_OK) { + if (ret != 0) { errno = getaddrinfo_error_to_errno(ret); return BHT_ERROR; } @@ -498,7 +519,7 @@ os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) ret = zsock_getsockname(socket->fd, (struct sockaddr *)&addr_storage, &addr_len); - if (ret != BHT_OK) { + if (ret != 0) { return BHT_ERROR; } @@ -515,7 +536,7 @@ os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) ret = zsock_getpeername(socket->fd, (struct sockaddr *)&addr_storage, &addr_len); - if (ret != BHT_OK) { + if (ret != 0) { return BHT_ERROR; } @@ -557,8 +578,9 @@ os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz) int os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz) { - if (zsock_setsockopt(socket->fd, SOL_SOCKET, SO_RCVBUF, &bufsiz, - sizeof(bufsiz)) + int opt = (int)bufsiz; + if (zsock_setsockopt(socket->fd, SOL_SOCKET, SO_RCVBUF, &opt, + sizeof(opt)) != 0) { return BHT_ERROR; } @@ -618,7 +640,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; } @@ -645,10 +667,10 @@ os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) int os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) { - struct timeval tv; + struct timeval tv = {0}; 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; } @@ -702,21 +724,34 @@ 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; + int on = is_enabled ? 1 : 0; + if (zsock_setsockopt(socket->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) { + /* Best-effort: ignore lack of support so connections don’t abort */ + if (errno == ENOPROTOOPT || errno == ENOSYS) { + return BHT_OK; + } + return BHT_ERROR; + } + return BHT_OK; } int os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled) { - errno = ENOSYS; - - return BHT_ERROR; + int on = 0; + socklen_t len = sizeof(on); + if (zsock_getsockopt(socket->fd, IPPROTO_TCP, TCP_NODELAY, &on, &len) != 0) { + if (errno == ENOPROTOOPT || errno == ENOSYS) { + *is_enabled = false; + return BHT_OK; + } + return BHT_ERROR; + } + *is_enabled = (on != 0); + return BHT_OK; } int @@ -769,8 +804,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; } @@ -778,8 +813,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; } @@ -895,7 +930,7 @@ os_socket_set_ip_add_membership(bh_socket_t socket, } mreq.ipv6mr_interface = imr_interface; - if (setsockopt(socket->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + if (zsock_setsockopt(socket->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0) { return BHT_ERROR; @@ -974,13 +1009,14 @@ 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); + int opt; + socklen_t opt_len = sizeof(opt); - if (zsock_setsockopt(socket->fd, IPPROTO_IP, IP_MULTICAST_TTL, ttl_s, - opt_len) + if (zsock_getsockopt(socket->fd, IPPROTO_IP, IP_TTL, &opt, &opt_len) != 0) { return BHT_ERROR; } + *ttl_s = (uint8_t)opt; return BHT_OK; } @@ -1000,13 +1036,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); + int opt; + socklen_t opt_len = sizeof(opt); - if (zsock_setsockopt(socket->fd, IPPROTO_IP, IP_MULTICAST_TTL, ttl_s, - opt_len) + 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; } From b59edc103a5e6c0f8e872e7e66379089709fe3a6 Mon Sep 17 00:00:00 2001 From: Dan Kouba Date: Tue, 21 Oct 2025 12:44:19 -0700 Subject: [PATCH 5/6] Implement functions required for pub/sub Signed-off-by: Dan Kouba --- core/shared/platform/zephyr/zephyr_socket.c | 148 +++++++++++++------- 1 file changed, 98 insertions(+), 50 deletions(-) diff --git a/core/shared/platform/zephyr/zephyr_socket.c b/core/shared/platform/zephyr/zephyr_socket.c index c19a2e5ae1..adab8cfd0e 100644 --- a/core/shared/platform/zephyr/zephyr_socket.c +++ b/core/shared/platform/zephyr/zephyr_socket.c @@ -900,19 +900,62 @@ 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; + int opt = is_enabled ? 1 : 0; + int ret; - return BHT_ERROR; +#ifdef IPPROTO_IPV6 + if (ipv6) { + ret = zsock_setsockopt(socket->fd, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, &opt, sizeof(opt)); + } else +#endif + { + ret = zsock_setsockopt(socket->fd, IPPROTO_IP, + IP_MULTICAST_LOOP, &opt, sizeof(opt)); + } + + if (ret != 0) { + /* Best-effort: some stacks don’t support this; don’t hard-fail */ + if (errno == ENOPROTOOPT || errno == ENOSYS) { + return BHT_OK; + } + return BHT_ERROR; + } + return BHT_OK; } int os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled) { - errno = ENOSYS; + int opt = 0; + socklen_t len = sizeof(opt); + int ret; - return BHT_ERROR; +#ifdef IPPROTO_IPV6 + if (ipv6) { + ret = zsock_getsockopt(socket->fd, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, &opt, &len); + } else +#endif + { + ret = zsock_getsockopt(socket->fd, IPPROTO_IP, + IP_MULTICAST_LOOP, &opt, &len); + } + + if (ret != 0) { + if (errno == ENOPROTOOPT || errno == ENOSYS) { + /* Report “disabled” if the stack doesn’t expose the knob */ + *is_enabled = false; + return BHT_OK; + } + return BHT_ERROR; + } + + *is_enabled = (opt != 0); + return BHT_OK; } + int os_socket_set_ip_add_membership(bh_socket_t socket, bh_ip_addr_buffer_t *imr_multiaddr, @@ -920,34 +963,37 @@ os_socket_set_ip_add_membership(bh_socket_t socket, { assert(imr_multiaddr); - if (is_ipv6) { -#if defined(IPPROTO_IPV6) && !defined(BH_PLATFORM_COSMOPOLITAN) - struct ipv6_mreq mreq; + int ret = -1; - for (int i = 0; i < 8; i++) { - ((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] = - imr_multiaddr->ipv6[i]; - } - mreq.ipv6mr_interface = imr_interface; +#ifdef IPPROTO_IPV6 + if (is_ipv6) { + struct ipv6_mreq mreq6 = {0}; + memcpy(&mreq6.ipv6mr_multiaddr, + &imr_multiaddr->ipv6[0], sizeof(mreq6.ipv6mr_multiaddr)); + mreq6.ipv6mr_interface = imr_interface; /* 0 ⇒ first suitable iface */ - if (zsock_setsockopt(socket->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)) - != 0) { - return BHT_ERROR; - } -#else - errno = EAFNOSUPPORT; - return BHT_ERROR; + ret = zsock_setsockopt(socket->fd, IPPROTO_IPV6, + IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)); + } else #endif - } - else { - struct ip_mreqn mreq; + { + struct ip_mreqn mreq = {0}; mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4; - mreq.imr_address.s_addr = imr_interface; + mreq.imr_address.s_addr = imr_interface; /* 0 ⇒ first suitable iface */ + /* mreq.imr_ifindex is optional; leave 0 unless you have an index */ + + ret = zsock_setsockopt(socket->fd, IPPROTO_IP, + IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + } - if (zsock_setsockopt(socket->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)) - != 0) { + if (ret != 0) { + 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; } } @@ -961,34 +1007,36 @@ os_socket_set_ip_drop_membership(bh_socket_t socket, { assert(imr_multiaddr); - if (is_ipv6) { -#if defined(IPPROTO_IPV6) && !defined(BH_PLATFORM_COSMOPOLITAN) - struct ipv6_mreq mreq; + int ret = -1; - for (int i = 0; i < 8; i++) { - ((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] = - imr_multiaddr->ipv6[i]; - } - mreq.ipv6mr_interface = imr_interface; +#ifdef IPPROTO_IPV6 + if (is_ipv6) { + struct ipv6_mreq mreq6 = {0}; + memcpy(&mreq6.ipv6mr_multiaddr, + &imr_multiaddr->ipv6[0], sizeof(mreq6.ipv6mr_multiaddr)); + mreq6.ipv6mr_interface = imr_interface; - if (zsock_setsockopt(socket->fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, - &mreq, sizeof(mreq)) - != 0) { - return BHT_ERROR; - } -#else - errno = EAFNOSUPPORT; - return BHT_ERROR; + ret = zsock_setsockopt(socket->fd, IPPROTO_IPV6, + IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)); + } else #endif - } - else { - struct ip_mreqn mreq; + { + struct ip_mreqn mreq = {0}; mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4; - mreq.imr_address.s_addr = imr_interface; + mreq.imr_address.s_addr = imr_interface; - if (zsock_setsockopt(socket->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, - sizeof(mreq)) - != 0) { + ret = zsock_setsockopt(socket->fd, IPPROTO_IP, + IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); + } + + if (ret != 0) { + switch (errno) { + case ENOENT: /* not a member: OK */ + case EINVAL: /* some stacks use this for “not joined” */ + case ENOPROTOOPT: + case ENOSYS: + return BHT_OK; + default: return BHT_ERROR; } } From 0936a04daaa08e65ddda9ab5ff271f600c09b896 Mon Sep 17 00:00:00 2001 From: Dan Kouba Date: Tue, 21 Oct 2025 12:44:47 -0700 Subject: [PATCH 6/6] Fix mismatch of enum sizes between WASM and host Signed-off-by: Dan Kouba --- .../platform/include/platform_wasi_types.h | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) 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 */