diff --git a/expected/wasm32-wasi-eh/defined-symbols.txt b/expected/wasm32-wasi-eh/defined-symbols.txt index ab98f67fb..e62c11d1b 100644 --- a/expected/wasm32-wasi-eh/defined-symbols.txt +++ b/expected/wasm32-wasi-eh/defined-symbols.txt @@ -488,8 +488,10 @@ __wasi_sock_open __wasi_sock_pair __wasi_sock_recv __wasi_sock_recv_from +__wasi_sock_recv_msg __wasi_sock_send __wasi_sock_send_file +__wasi_sock_send_msg __wasi_sock_send_to __wasi_sock_set_opt_flag __wasi_sock_set_opt_size diff --git a/expected/wasm32-wasi-eh/predefined-macros.txt b/expected/wasm32-wasi-eh/predefined-macros.txt index 826a19ac0..165d26cde 100644 --- a/expected/wasm32-wasi-eh/predefined-macros.txt +++ b/expected/wasm32-wasi-eh/predefined-macros.txt @@ -220,6 +220,12 @@ #define CMPLX(x,y) __CMPLX(x, y, double) #define CMPLXF(x,y) __CMPLX(x, y, float) #define CMPLXL(x,y) __CMPLX(x, y, long double) +#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) +#define CMSG_DATA(cmsg) ((unsigned char *) (((struct cmsghdr *)(cmsg)) + 1)) +#define CMSG_FIRSTHDR(mhdr) ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) 0) +#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +#define CMSG_NXTHDR(mhdr,cmsg) ((cmsg)->cmsg_len < sizeof (struct cmsghdr) || __CMSG_LEN(cmsg) + sizeof(struct cmsghdr) >= __MHDR_END(mhdr) - (unsigned char *)(cmsg) ? 0 : (struct cmsghdr *)__CMSG_NEXT(cmsg)) +#define CMSG_SPACE(len) (CMSG_ALIGN (len) + CMSG_ALIGN (sizeof (struct cmsghdr))) #define CMSPAR 010000000000 #define CODESET 14 #define COLL_WEIGHTS_MAX 2 @@ -4148,6 +4154,8 @@ #define SCHED_OTHER 0 #define SCHED_RESET_ON_FORK 0x40000000 #define SCHED_RR 2 +#define SCM_CREDENTIALS 0x02 +#define SCM_RIGHTS 0x01 #define SCNd16 __INT16_FMTd__ #define SCNd32 __INT32_FMTd__ #define SCNd64 __INT64_FMTd__ @@ -5474,6 +5482,8 @@ #define __compiler_ATOMIC_WCHAR_T_LOCK_FREE 2 #define __CLANG_MAX_ALIGN_T_DEFINED #define __CMPLX(x,y,t) (__builtin_complex((t)(x), (t)(y))) +#define __CMSG_LEN(cmsg) (((cmsg)->cmsg_len + sizeof(long) - 1) & ~(long)(sizeof(long) - 1)) +#define __CMSG_NEXT(cmsg) ((unsigned char *)(cmsg) + __CMSG_LEN(cmsg)) #define __CONSTANT_CFSTRINGS__ 1 #define __CPU_op_S(i,size,set,op) ( (i)/8U >= (size) ? 0 : (((unsigned long *)(set))[(i)/8/sizeof(long)] op (1UL<<((i)%(8*sizeof(long))))) ) #define __CPU_op_func_S(func,op) static __inline void __CPU_##func##_S(size_t __size, cpu_set_t *__dest, const cpu_set_t *__src1, const cpu_set_t *__src2) { size_t __i; for (__i=0; __i<__size/sizeof(long); __i++) ((unsigned long *)__dest)[__i] = ((unsigned long *)__src1)[__i] op ((unsigned long *)__src2)[__i] ; } @@ -5707,6 +5717,7 @@ #define __MEMORY_SCOPE_SYSTEM 0 #define __MEMORY_SCOPE_WRKGRP 2 #define __MEMORY_SCOPE_WVFRNT 3 +#define __MHDR_END(mhdr) ((unsigned char *)(mhdr)->msg_control + (mhdr)->msg_controllen) #define __NAMESER 19991006 #define __NEED_FILE #define __NEED___isoc_va_list @@ -6202,6 +6213,8 @@ #define __WASI_SIGNAL_WINCH (UINT8_C(28)) #define __WASI_SIGNAL_XCPU (UINT8_C(24)) #define __WASI_SIGNAL_XFSZ (UINT8_C(25)) +#define __WASI_SOCK_CMSG_LEVEL_SOCKET (UINT16_C(0)) +#define __WASI_SOCK_CMSG_TYPE_RIGHTS (UINT16_C(0)) #define __WASI_SOCK_OPTION_ACCEPT_TIMEOUT (UINT8_C(22)) #define __WASI_SOCK_OPTION_BROADCAST (UINT8_C(6)) #define __WASI_SOCK_OPTION_CONNECT_TIMEOUT (UINT8_C(21)) diff --git a/expected/wasm32-wasi-eh/undefined-symbols.txt b/expected/wasm32-wasi-eh/undefined-symbols.txt index b66aa7377..e05302ec7 100644 --- a/expected/wasm32-wasi-eh/undefined-symbols.txt +++ b/expected/wasm32-wasi-eh/undefined-symbols.txt @@ -133,7 +133,9 @@ __imported_wasix_32v1_sock_listen __imported_wasix_32v1_sock_open __imported_wasix_32v1_sock_pair __imported_wasix_32v1_sock_recv_from +__imported_wasix_32v1_sock_recv_msg __imported_wasix_32v1_sock_send_file +__imported_wasix_32v1_sock_send_msg __imported_wasix_32v1_sock_send_to __imported_wasix_32v1_sock_set_opt_flag __imported_wasix_32v1_sock_set_opt_size diff --git a/expected/wasm32-wasi-ehpic/defined-symbols.txt b/expected/wasm32-wasi-ehpic/defined-symbols.txt index 03182322a..ae578e313 100644 --- a/expected/wasm32-wasi-ehpic/defined-symbols.txt +++ b/expected/wasm32-wasi-ehpic/defined-symbols.txt @@ -491,8 +491,10 @@ __wasi_sock_open __wasi_sock_pair __wasi_sock_recv __wasi_sock_recv_from +__wasi_sock_recv_msg __wasi_sock_send __wasi_sock_send_file +__wasi_sock_send_msg __wasi_sock_send_to __wasi_sock_set_opt_flag __wasi_sock_set_opt_size diff --git a/expected/wasm32-wasi-ehpic/predefined-macros.txt b/expected/wasm32-wasi-ehpic/predefined-macros.txt index 8081fbcf5..ecd53abb8 100644 --- a/expected/wasm32-wasi-ehpic/predefined-macros.txt +++ b/expected/wasm32-wasi-ehpic/predefined-macros.txt @@ -220,6 +220,12 @@ #define CMPLX(x,y) __CMPLX(x, y, double) #define CMPLXF(x,y) __CMPLX(x, y, float) #define CMPLXL(x,y) __CMPLX(x, y, long double) +#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) +#define CMSG_DATA(cmsg) ((unsigned char *) (((struct cmsghdr *)(cmsg)) + 1)) +#define CMSG_FIRSTHDR(mhdr) ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) 0) +#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +#define CMSG_NXTHDR(mhdr,cmsg) ((cmsg)->cmsg_len < sizeof (struct cmsghdr) || __CMSG_LEN(cmsg) + sizeof(struct cmsghdr) >= __MHDR_END(mhdr) - (unsigned char *)(cmsg) ? 0 : (struct cmsghdr *)__CMSG_NEXT(cmsg)) +#define CMSG_SPACE(len) (CMSG_ALIGN (len) + CMSG_ALIGN (sizeof (struct cmsghdr))) #define CMSPAR 010000000000 #define CODESET 14 #define COLL_WEIGHTS_MAX 2 @@ -4155,6 +4161,8 @@ #define SCHED_OTHER 0 #define SCHED_RESET_ON_FORK 0x40000000 #define SCHED_RR 2 +#define SCM_CREDENTIALS 0x02 +#define SCM_RIGHTS 0x01 #define SCNd16 __INT16_FMTd__ #define SCNd32 __INT32_FMTd__ #define SCNd64 __INT64_FMTd__ @@ -5482,6 +5490,8 @@ #define __compiler_ATOMIC_WCHAR_T_LOCK_FREE 2 #define __CLANG_MAX_ALIGN_T_DEFINED #define __CMPLX(x,y,t) (__builtin_complex((t)(x), (t)(y))) +#define __CMSG_LEN(cmsg) (((cmsg)->cmsg_len + sizeof(long) - 1) & ~(long)(sizeof(long) - 1)) +#define __CMSG_NEXT(cmsg) ((unsigned char *)(cmsg) + __CMSG_LEN(cmsg)) #define __CONSTANT_CFSTRINGS__ 1 #define __CPU_op_S(i,size,set,op) ( (i)/8U >= (size) ? 0 : (((unsigned long *)(set))[(i)/8/sizeof(long)] op (1UL<<((i)%(8*sizeof(long))))) ) #define __CPU_op_func_S(func,op) static __inline void __CPU_##func##_S(size_t __size, cpu_set_t *__dest, const cpu_set_t *__src1, const cpu_set_t *__src2) { size_t __i; for (__i=0; __i<__size/sizeof(long); __i++) ((unsigned long *)__dest)[__i] = ((unsigned long *)__src1)[__i] op ((unsigned long *)__src2)[__i] ; } @@ -5715,6 +5725,7 @@ #define __MEMORY_SCOPE_SYSTEM 0 #define __MEMORY_SCOPE_WRKGRP 2 #define __MEMORY_SCOPE_WVFRNT 3 +#define __MHDR_END(mhdr) ((unsigned char *)(mhdr)->msg_control + (mhdr)->msg_controllen) #define __NAMESER 19991006 #define __NEED_FILE #define __NEED___isoc_va_list @@ -6211,6 +6222,8 @@ #define __WASI_SIGNAL_WINCH (UINT8_C(28)) #define __WASI_SIGNAL_XCPU (UINT8_C(24)) #define __WASI_SIGNAL_XFSZ (UINT8_C(25)) +#define __WASI_SOCK_CMSG_LEVEL_SOCKET (UINT16_C(0)) +#define __WASI_SOCK_CMSG_TYPE_RIGHTS (UINT16_C(0)) #define __WASI_SOCK_OPTION_ACCEPT_TIMEOUT (UINT8_C(22)) #define __WASI_SOCK_OPTION_BROADCAST (UINT8_C(6)) #define __WASI_SOCK_OPTION_CONNECT_TIMEOUT (UINT8_C(21)) diff --git a/expected/wasm32-wasi-ehpic/undefined-symbols.txt b/expected/wasm32-wasi-ehpic/undefined-symbols.txt index 15087979e..efd88a460 100644 --- a/expected/wasm32-wasi-ehpic/undefined-symbols.txt +++ b/expected/wasm32-wasi-ehpic/undefined-symbols.txt @@ -134,7 +134,9 @@ __imported_wasix_32v1_sock_listen __imported_wasix_32v1_sock_open __imported_wasix_32v1_sock_pair __imported_wasix_32v1_sock_recv_from +__imported_wasix_32v1_sock_recv_msg __imported_wasix_32v1_sock_send_file +__imported_wasix_32v1_sock_send_msg __imported_wasix_32v1_sock_send_to __imported_wasix_32v1_sock_set_opt_flag __imported_wasix_32v1_sock_set_opt_size diff --git a/expected/wasm32-wasi-threads/defined-symbols.txt b/expected/wasm32-wasi-threads/defined-symbols.txt index c8996ef3b..9cc7768b7 100644 --- a/expected/wasm32-wasi-threads/defined-symbols.txt +++ b/expected/wasm32-wasi-threads/defined-symbols.txt @@ -456,9 +456,11 @@ __wasi_sock_leave_multicast_v6 __wasi_sock_listen __wasi_sock_open __wasi_sock_recv +__wasi_sock_recv_msg __wasi_sock_recv_from __wasi_sock_send __wasi_sock_send_file +__wasi_sock_send_msg __wasi_sock_send_to __wasi_sock_set_opt_flag __wasi_sock_set_opt_size diff --git a/expected/wasm32-wasi-threads/undefined-symbols.txt b/expected/wasm32-wasi-threads/undefined-symbols.txt index e4a263820..05d743522 100644 --- a/expected/wasm32-wasi-threads/undefined-symbols.txt +++ b/expected/wasm32-wasi-threads/undefined-symbols.txt @@ -110,8 +110,10 @@ __imported_wasix_32v1_sock_leave_multicast_v4 __imported_wasix_32v1_sock_leave_multicast_v6 __imported_wasix_32v1_sock_listen __imported_wasix_32v1_sock_open +__imported_wasix_32v1_sock_recv_msg __imported_wasix_32v1_sock_recv_from __imported_wasix_32v1_sock_send_file +__imported_wasix_32v1_sock_send_msg __imported_wasix_32v1_sock_send_to __imported_wasix_32v1_sock_set_opt_flag __imported_wasix_32v1_sock_set_opt_size diff --git a/expected/wasm32-wasi/defined-symbols.txt b/expected/wasm32-wasi/defined-symbols.txt index 1e9b0707a..6a1f94a11 100644 --- a/expected/wasm32-wasi/defined-symbols.txt +++ b/expected/wasm32-wasi/defined-symbols.txt @@ -489,8 +489,10 @@ __wasi_sock_open __wasi_sock_pair __wasi_sock_recv __wasi_sock_recv_from +__wasi_sock_recv_msg __wasi_sock_send __wasi_sock_send_file +__wasi_sock_send_msg __wasi_sock_send_to __wasi_sock_set_opt_flag __wasi_sock_set_opt_size diff --git a/expected/wasm32-wasi/predefined-macros.txt b/expected/wasm32-wasi/predefined-macros.txt index d75a22804..f224638d5 100644 --- a/expected/wasm32-wasi/predefined-macros.txt +++ b/expected/wasm32-wasi/predefined-macros.txt @@ -220,6 +220,12 @@ #define CMPLX(x,y) __CMPLX(x, y, double) #define CMPLXF(x,y) __CMPLX(x, y, float) #define CMPLXL(x,y) __CMPLX(x, y, long double) +#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) +#define CMSG_DATA(cmsg) ((unsigned char *) (((struct cmsghdr *)(cmsg)) + 1)) +#define CMSG_FIRSTHDR(mhdr) ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) 0) +#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +#define CMSG_NXTHDR(mhdr,cmsg) ((cmsg)->cmsg_len < sizeof (struct cmsghdr) || __CMSG_LEN(cmsg) + sizeof(struct cmsghdr) >= __MHDR_END(mhdr) - (unsigned char *)(cmsg) ? 0 : (struct cmsghdr *)__CMSG_NEXT(cmsg)) +#define CMSG_SPACE(len) (CMSG_ALIGN (len) + CMSG_ALIGN (sizeof (struct cmsghdr))) #define CMSPAR 010000000000 #define CODESET 14 #define COLL_WEIGHTS_MAX 2 @@ -4155,6 +4161,8 @@ #define SCHED_OTHER 0 #define SCHED_RESET_ON_FORK 0x40000000 #define SCHED_RR 2 +#define SCM_CREDENTIALS 0x02 +#define SCM_RIGHTS 0x01 #define SCNd16 __INT16_FMTd__ #define SCNd32 __INT32_FMTd__ #define SCNd64 __INT64_FMTd__ @@ -5482,6 +5490,8 @@ #define __compiler_ATOMIC_WCHAR_T_LOCK_FREE 2 #define __CLANG_MAX_ALIGN_T_DEFINED #define __CMPLX(x,y,t) (__builtin_complex((t)(x), (t)(y))) +#define __CMSG_LEN(cmsg) (((cmsg)->cmsg_len + sizeof(long) - 1) & ~(long)(sizeof(long) - 1)) +#define __CMSG_NEXT(cmsg) ((unsigned char *)(cmsg) + __CMSG_LEN(cmsg)) #define __CONSTANT_CFSTRINGS__ 1 #define __CPU_op_S(i,size,set,op) ( (i)/8U >= (size) ? 0 : (((unsigned long *)(set))[(i)/8/sizeof(long)] op (1UL<<((i)%(8*sizeof(long))))) ) #define __CPU_op_func_S(func,op) static __inline void __CPU_##func##_S(size_t __size, cpu_set_t *__dest, const cpu_set_t *__src1, const cpu_set_t *__src2) { size_t __i; for (__i=0; __i<__size/sizeof(long); __i++) ((unsigned long *)__dest)[__i] = ((unsigned long *)__src1)[__i] op ((unsigned long *)__src2)[__i] ; } @@ -5715,6 +5725,7 @@ #define __MEMORY_SCOPE_SYSTEM 0 #define __MEMORY_SCOPE_WRKGRP 2 #define __MEMORY_SCOPE_WVFRNT 3 +#define __MHDR_END(mhdr) ((unsigned char *)(mhdr)->msg_control + (mhdr)->msg_controllen) #define __NAMESER 19991006 #define __NEED_FILE #define __NEED___isoc_va_list @@ -6210,6 +6221,8 @@ #define __WASI_SIGNAL_WINCH (UINT8_C(28)) #define __WASI_SIGNAL_XCPU (UINT8_C(24)) #define __WASI_SIGNAL_XFSZ (UINT8_C(25)) +#define __WASI_SOCK_CMSG_LEVEL_SOCKET (UINT16_C(0)) +#define __WASI_SOCK_CMSG_TYPE_RIGHTS (UINT16_C(0)) #define __WASI_SOCK_OPTION_ACCEPT_TIMEOUT (UINT8_C(22)) #define __WASI_SOCK_OPTION_BROADCAST (UINT8_C(6)) #define __WASI_SOCK_OPTION_CONNECT_TIMEOUT (UINT8_C(21)) diff --git a/expected/wasm32-wasi/undefined-symbols.txt b/expected/wasm32-wasi/undefined-symbols.txt index b66aa7377..e05302ec7 100644 --- a/expected/wasm32-wasi/undefined-symbols.txt +++ b/expected/wasm32-wasi/undefined-symbols.txt @@ -133,7 +133,9 @@ __imported_wasix_32v1_sock_listen __imported_wasix_32v1_sock_open __imported_wasix_32v1_sock_pair __imported_wasix_32v1_sock_recv_from +__imported_wasix_32v1_sock_recv_msg __imported_wasix_32v1_sock_send_file +__imported_wasix_32v1_sock_send_msg __imported_wasix_32v1_sock_send_to __imported_wasix_32v1_sock_set_opt_flag __imported_wasix_32v1_sock_set_opt_size diff --git a/expected/wasm64-wasi/defined-symbols.txt b/expected/wasm64-wasi/defined-symbols.txt index cd3d45b83..5cf32ab65 100644 --- a/expected/wasm64-wasi/defined-symbols.txt +++ b/expected/wasm64-wasi/defined-symbols.txt @@ -460,9 +460,11 @@ __wasi_sock_leave_multicast_v6 __wasi_sock_listen __wasi_sock_open __wasi_sock_recv +__wasi_sock_recv_msg __wasi_sock_recv_from __wasi_sock_send __wasi_sock_send_file +__wasi_sock_send_msg __wasi_sock_send_to __wasi_sock_set_opt_flag __wasi_sock_set_opt_size diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/socket/recvmsg.c b/libc-bottom-half/cloudlibc/src/libc/sys/socket/recvmsg.c index 74b404ead..e5e02fa13 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sys/socket/recvmsg.c +++ b/libc-bottom-half/cloudlibc/src/libc/sys/socket/recvmsg.c @@ -7,7 +7,67 @@ #include #include #include +#include #include +#include + +static size_t wasi_cmsg_align(size_t len) { + return (len + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1); +} + +static int convert_control_from_wasi(struct msghdr* msg, + const uint8_t* control, + size_t control_len) { + if (msg->msg_control == NULL || msg->msg_controllen == 0) { + if (control_len != 0) + msg->msg_flags |= MSG_CTRUNC; + msg->msg_controllen = 0; + return 0; + } + + uint8_t* out = msg->msg_control; + size_t out_capacity = msg->msg_controllen; + size_t out_used = 0; + size_t in_offset = 0; + + while (in_offset + sizeof(__wasi_sock_cmsg_t) <= control_len) { + const __wasi_sock_cmsg_t* wasi_cmsg = + (const __wasi_sock_cmsg_t*)(control + in_offset); + if (wasi_cmsg->cmsg_len < sizeof(__wasi_sock_cmsg_t) || + in_offset + wasi_cmsg->cmsg_len > control_len) { + msg->msg_flags |= MSG_CTRUNC; + break; + } + + size_t payload_len = wasi_cmsg->cmsg_len - sizeof(__wasi_sock_cmsg_t); + size_t posix_space = CMSG_SPACE(payload_len); + size_t posix_len = CMSG_LEN(payload_len); + if (out_used + posix_space > out_capacity) { + msg->msg_flags |= MSG_CTRUNC; + break; + } + + struct cmsghdr* cmsg = (struct cmsghdr*)(out + out_used); + if (wasi_cmsg->cmsg_level == __WASI_SOCK_CMSG_LEVEL_SOCKET && + wasi_cmsg->cmsg_type == __WASI_SOCK_CMSG_TYPE_RIGHTS) { + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + } else { + msg->msg_flags |= MSG_CTRUNC; + break; + } + + cmsg->cmsg_len = posix_len; + memcpy(CMSG_DATA(cmsg), + control + in_offset + wasi_cmsg_align(sizeof(__wasi_sock_cmsg_t)), + payload_len); + out_used += posix_space; + in_offset += wasi_cmsg_align(sizeof(__wasi_sock_cmsg_t)) + wasi_cmsg_align(payload_len); + } + + msg->msg_controllen = out_used; + return 0; +} ssize_t recvmsg(int socket, struct msghdr *restrict msg, int flags) { __wasi_iovec_t *ri_data = (__wasi_iovec_t *)msg->msg_iov; @@ -21,12 +81,39 @@ ssize_t recvmsg(int socket, struct msghdr *restrict msg, int flags) { __wasi_size_t ro_datalen; __wasi_roflags_t ro_flags; + __wasi_size_t ro_control_len = 0; __wasi_errno_t error; - if (msg->msg_name == NULL) { + + uint8_t* control = NULL; + size_t control_capacity = msg->msg_control == NULL ? 0 : msg->msg_controllen; + if (control_capacity != 0) { + control = malloc(control_capacity); + if (control == NULL) { + errno = ENOMEM; + return -1; + } + } + + if (control_capacity != 0) { + __wasi_addr_port_t peer_addr; + __wasi_addr_port_t* peer_addr_ptr = msg->msg_name == NULL ? NULL : &peer_addr; + error = __wasi_sock_recv_msg(socket, + ri_data, ri_data_len, ri_flags, + peer_addr_ptr, + control, control_capacity, + &ro_datalen, + &ro_flags, + &ro_control_len); + if (error == 0 && msg->msg_name != NULL) { + struct sockaddr *addr = (struct sockaddr *)msg->msg_name; + socklen_t *addrlen = &msg->msg_namelen; + error = wasi_to_sockaddr(&peer_addr, addr, addrlen); + } + } else if (msg->msg_name == NULL) { error = __wasi_sock_recv(socket, - ri_data, ri_data_len, ri_flags, - &ro_datalen, - &ro_flags); + ri_data, ri_data_len, ri_flags, + &ro_datalen, + &ro_flags); } else { __wasi_addr_port_t peer_addr; error = __wasi_sock_recv_from(socket, @@ -41,9 +128,19 @@ ssize_t recvmsg(int socket, struct msghdr *restrict msg, int flags) { struct sockaddr *addr = (struct sockaddr *)msg->msg_name; socklen_t *addrlen = &msg->msg_namelen; - error = wasi_to_sockaddr(&peer_addr, addr, addrlen); + error = wasi_to_sockaddr(&peer_addr, addr, addrlen); + } + msg->msg_flags = 0; + if ((ro_flags & __WASI_ROFLAGS_RECV_DATA_TRUNCATED) != 0) + msg->msg_flags |= MSG_TRUNC; + if (error == 0 && control_capacity != 0) { + if (ro_control_len > control_capacity) + msg->msg_flags |= MSG_CTRUNC; + convert_control_from_wasi(msg, control, ro_control_len > control_capacity ? control_capacity : ro_control_len); + } else if (control_capacity == 0) { + msg->msg_controllen = 0; } - msg->msg_flags = ro_flags; + free(control); if (error != 0) { errno = error; diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/socket/sendmsg.c b/libc-bottom-half/cloudlibc/src/libc/sys/socket/sendmsg.c index f161afed9..c98af8479 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sys/socket/sendmsg.c +++ b/libc-bottom-half/cloudlibc/src/libc/sys/socket/sendmsg.c @@ -7,7 +7,67 @@ #include #include #include +#include #include +#include + +static size_t wasi_cmsg_align(size_t len) { + return (len + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1); +} + +static int convert_control_to_wasi(const struct msghdr* msg, + uint8_t** out_control, + size_t* out_control_len) { + *out_control = NULL; + *out_control_len = 0; + + if (msg->msg_control == NULL || msg->msg_controllen == 0) + return 0; + + size_t len = 0; + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + errno = ENOTSUP; + return -1; + } + if (cmsg->cmsg_len < CMSG_LEN(0)) { + errno = EINVAL; + return -1; + } + size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0); + len += wasi_cmsg_align(sizeof(__wasi_sock_cmsg_t)) + wasi_cmsg_align(payload_len); + } + + if (len == 0) + return 0; + + uint8_t* control = malloc(len); + if (control == NULL) { + errno = ENOMEM; + return -1; + } + + uint8_t* out = control; + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) { + size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0); + __wasi_sock_cmsg_t* wasi_cmsg = (__wasi_sock_cmsg_t*)out; + wasi_cmsg->cmsg_len = sizeof(__wasi_sock_cmsg_t) + payload_len; + wasi_cmsg->cmsg_level = __WASI_SOCK_CMSG_LEVEL_SOCKET; + wasi_cmsg->cmsg_type = __WASI_SOCK_CMSG_TYPE_RIGHTS; + memcpy(out + wasi_cmsg_align(sizeof(__wasi_sock_cmsg_t)), + CMSG_DATA(cmsg), + payload_len); + out += wasi_cmsg_align(sizeof(__wasi_sock_cmsg_t)) + wasi_cmsg_align(payload_len); + } + + *out_control = control; + *out_control_len = len; + return 0; +} ssize_t sendmsg(int socket, const struct msghdr* msg, int flags) { if (msg->msg_iov == NULL) { @@ -24,19 +84,32 @@ ssize_t sendmsg(int socket, const struct msghdr* msg, int flags) { if ((flags & MSG_DONTWAIT) != 0) { si_flags |= __WASI_SIFLAGS_SEND_DONT_WAIT; } + uint8_t* control = NULL; + size_t control_len = 0; + if (convert_control_to_wasi(msg, &control, &control_len) != 0) + return -1; + if (msg->msg_name == NULL) { - error = __wasi_sock_send(socket, si_data, si_data_len, si_flags, &so_datalen); + error = control_len == 0 + ? __wasi_sock_send(socket, si_data, si_data_len, si_flags, &so_datalen) + : __wasi_sock_send_msg(socket, si_data, si_data_len, si_flags, NULL, + control, control_len, &so_datalen); } else { struct sockaddr *addr = (struct sockaddr *)msg->msg_name; socklen_t addrlen = msg->msg_namelen; __wasi_addr_port_t peer_addr; error = sockaddr_to_wasi(addr, addrlen, &peer_addr); if (error != 0) { + free(control); errno = error; return -1; } - error = __wasi_sock_send_to(socket, si_data, si_data_len, si_flags, &peer_addr, &so_datalen); + error = control_len == 0 + ? __wasi_sock_send_to(socket, si_data, si_data_len, si_flags, &peer_addr, &so_datalen) + : __wasi_sock_send_msg(socket, si_data, si_data_len, si_flags, &peer_addr, + control, control_len, &so_datalen); } + free(control); if (error != 0) { errno = error; diff --git a/libc-bottom-half/headers/public/__header_sys_socket.h b/libc-bottom-half/headers/public/__header_sys_socket.h index f14519789..6d0db9040 100644 --- a/libc-bottom-half/headers/public/__header_sys_socket.h +++ b/libc-bottom-half/headers/public/__header_sys_socket.h @@ -42,6 +42,23 @@ #define MSG_FASTOPEN 0x20000000 #define MSG_CMSG_CLOEXEC 0x40000000 +#define __CMSG_LEN(cmsg) (((cmsg)->cmsg_len + sizeof(long) - 1) & ~(long)(sizeof(long) - 1)) +#define __CMSG_NEXT(cmsg) ((unsigned char *)(cmsg) + __CMSG_LEN(cmsg)) +#define __MHDR_END(mhdr) ((unsigned char *)(mhdr)->msg_control + (mhdr)->msg_controllen) + +#define CMSG_DATA(cmsg) ((unsigned char *) (((struct cmsghdr *)(cmsg)) + 1)) +#define CMSG_NXTHDR(mhdr, cmsg) ((cmsg)->cmsg_len < sizeof (struct cmsghdr) || \ + __CMSG_LEN(cmsg) + sizeof(struct cmsghdr) >= __MHDR_END(mhdr) - (unsigned char *)(cmsg) \ + ? 0 : (struct cmsghdr *)__CMSG_NEXT(cmsg)) +#define CMSG_FIRSTHDR(mhdr) ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) 0) + +#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) +#define CMSG_SPACE(len) (CMSG_ALIGN (len) + CMSG_ALIGN (sizeof (struct cmsghdr))) +#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + +#define SCM_RIGHTS 0x01 +#define SCM_CREDENTIALS 0x02 + #define SOCK_DGRAM __WASI_SOCK_TYPE_SOCKET_DGRAM #define SOCK_STREAM __WASI_SOCK_TYPE_SOCKET_STREAM #define SOCK_RAW __WASI_SOCK_TYPE_SOCKET_RAW diff --git a/libc-bottom-half/headers/public/__struct_msghdr.h b/libc-bottom-half/headers/public/__struct_msghdr.h index 0c0877dc1..5e89ee780 100644 --- a/libc-bottom-half/headers/public/__struct_msghdr.h +++ b/libc-bottom-half/headers/public/__struct_msghdr.h @@ -13,4 +13,10 @@ struct msghdr { int msg_flags; }; +struct cmsghdr { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; +}; + #endif diff --git a/libc-bottom-half/headers/public/wasi/api_wasix.h b/libc-bottom-half/headers/public/wasi/api_wasix.h index e43aa20c8..e09f38c96 100644 --- a/libc-bottom-half/headers/public/wasi/api_wasix.h +++ b/libc-bottom-half/headers/public/wasi/api_wasix.h @@ -1414,6 +1414,61 @@ typedef uint16_t __wasi_siflags_t; */ #define __WASI_SIFLAGS_SEND_DONT_WAIT ((__wasi_siflags_t)+(1 << 0)) +/** + * Socket control message level. + */ +typedef uint16_t __wasi_sock_cmsg_level_t; + +/** + * POSIX SOL_SOCKET. + */ +#define __WASI_SOCK_CMSG_LEVEL_SOCKET (UINT16_C(0)) + +_Static_assert(sizeof(__wasi_sock_cmsg_level_t) == 2, "witx calculated size"); +_Static_assert(_Alignof(__wasi_sock_cmsg_level_t) == 2, "witx calculated align"); + +/** + * Socket control message type. + */ +typedef uint16_t __wasi_sock_cmsg_type_t; + +/** + * POSIX SCM_RIGHTS. Payload is an array of file descriptors. + */ +#define __WASI_SOCK_CMSG_TYPE_RIGHTS (UINT16_C(0)) + +_Static_assert(sizeof(__wasi_sock_cmsg_type_t) == 2, "witx calculated size"); +_Static_assert(_Alignof(__wasi_sock_cmsg_type_t) == 2, "witx calculated align"); + +/** + * Socket control message header. + * + * Payload bytes immediately follow this header in the control buffer. + */ +typedef struct __wasi_sock_cmsg_t { + /** + * Header plus payload size in bytes. + */ + __wasi_size_t cmsg_len; + + /** + * Control message level. + */ + __wasi_sock_cmsg_level_t cmsg_level; + + /** + * Control message type. + */ + __wasi_sock_cmsg_type_t cmsg_type; + +} __wasi_sock_cmsg_t; + +_Static_assert(sizeof(__wasi_sock_cmsg_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_sock_cmsg_t) == 4, "witx calculated align"); +_Static_assert(offsetof(__wasi_sock_cmsg_t, cmsg_len) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_sock_cmsg_t, cmsg_level) == 4, "witx calculated offset"); +_Static_assert(offsetof(__wasi_sock_cmsg_t, cmsg_type) == 6, "witx calculated offset"); + /** *** Hidden type typedef uint8_t __wasi_sdflags_t; @@ -5053,6 +5108,83 @@ __wasi_errno_t __wasi_sock_send_to( const __wasi_addr_port_t * addr, __wasi_size_t *retptr0 ) __attribute__((__warn_unused_result__)); +/** + * Receive a message, optional peer address, and optional ancillary data from + * a socket. + * + * Note: This is similar to `recvmsg` in POSIX, though it also supports + * reading the data into multiple buffers in the manner of `readv`. + * @return + * Number of bytes stored in ri_data, message flags, and number of bytes + * stored in ro_control. + */ +__wasi_errno_t __wasi_sock_recv_msg( + __wasi_fd_t fd, + /** + * List of scatter/gather vectors to which to store data. + */ + const __wasi_iovec_t *ri_data, + /** + * The length of the array pointed to by `ri_data`. + */ + size_t ri_data_len, + /** + * Message flags. + */ + __wasi_riflags_t ri_flags, + /** + * Optional output peer address. Null means the caller does not request it. + */ + __wasi_addr_port_t * addr, + /** + * Output control-message buffer. + */ + uint8_t * ro_control, + /** + * Capacity of ro_control in bytes. + */ + __wasi_size_t ro_control_len, + __wasi_size_t *retptr0, + __wasi_roflags_t *retptr1, + __wasi_size_t *retptr2 +) __attribute__((__warn_unused_result__)); +/** + * Send a message, optional peer address, and optional ancillary data on a + * socket. + * + * Note: This is similar to `sendmsg` in POSIX, though it also supports + * writing the data from multiple buffers in the manner of `writev`. + * @return + * Number of bytes transmitted. + */ +__wasi_errno_t __wasi_sock_send_msg( + __wasi_fd_t fd, + /** + * List of scatter/gather vectors from which to retrieve data. + */ + const __wasi_ciovec_t *si_data, + /** + * The length of the array pointed to by `si_data`. + */ + size_t si_data_len, + /** + * Message flags. + */ + __wasi_siflags_t si_flags, + /** + * Optional peer address. Null means connected socket / no explicit address. + */ + const __wasi_addr_port_t * addr, + /** + * Input control-message buffer. + */ + const uint8_t * si_control, + /** + * Size of si_control in bytes. + */ + __wasi_size_t si_control_len, + __wasi_size_t *retptr0 +) __attribute__((__warn_unused_result__)); /** * Sends the entire contents of a file down a socket * @return diff --git a/libc-bottom-half/sources/__wasixlibc_real.c b/libc-bottom-half/sources/__wasixlibc_real.c index e16d1b8cf..aff890a35 100644 --- a/libc-bottom-half/sources/__wasixlibc_real.c +++ b/libc-bottom-half/sources/__wasixlibc_real.c @@ -1087,6 +1087,46 @@ __wasi_errno_t __wasi_sock_send_to( return (uint16_t) ret; } +int32_t __imported_wasix_32v1_sock_recv_msg(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7, int32_t arg8, int32_t arg9) __attribute__(( + __import_module__("wasix_32v1"), + __import_name__("sock_recv_msg") +)); + +__wasi_errno_t __wasi_sock_recv_msg( + __wasi_fd_t fd, + const __wasi_iovec_t *ri_data, + size_t ri_data_len, + __wasi_riflags_t ri_flags, + __wasi_addr_port_t * addr, + uint8_t * ro_control, + __wasi_size_t ro_control_len, + __wasi_size_t *retptr0, + __wasi_roflags_t *retptr1, + __wasi_size_t *retptr2 +){ + int32_t ret = __imported_wasix_32v1_sock_recv_msg((int32_t) fd, (intptr_t) ri_data, (intptr_t) ri_data_len, ri_flags, (int32_t) addr, (int32_t) ro_control, (int32_t) ro_control_len, (intptr_t) retptr0, (intptr_t) retptr1, (intptr_t) retptr2); + return (uint16_t) ret; +} + +int32_t __imported_wasix_32v1_sock_send_msg(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7) __attribute__(( + __import_module__("wasix_32v1"), + __import_name__("sock_send_msg") +)); + +__wasi_errno_t __wasi_sock_send_msg( + __wasi_fd_t fd, + const __wasi_ciovec_t *si_data, + size_t si_data_len, + __wasi_siflags_t si_flags, + const __wasi_addr_port_t * addr, + const uint8_t * si_control, + __wasi_size_t si_control_len, + __wasi_size_t *retptr0 +){ + int32_t ret = __imported_wasix_32v1_sock_send_msg((int32_t) fd, (intptr_t) si_data, (intptr_t) si_data_len, si_flags, (int32_t) addr, (int32_t) si_control, (int32_t) si_control_len, (intptr_t) retptr0); + return (uint16_t) ret; +} + int32_t __imported_wasix_32v1_sock_send_file(int32_t arg0, int32_t arg1, int64_t arg2, int64_t arg3, int32_t arg4) __attribute__(( __import_module__("wasix_32v1"), __import_name__("sock_send_file") diff --git a/tools/wasix-headers/WASI b/tools/wasix-headers/WASI index 0dfbd35a0..2d4284a0b 160000 --- a/tools/wasix-headers/WASI +++ b/tools/wasix-headers/WASI @@ -1 +1 @@ -Subproject commit 0dfbd35a0f30f3fe7fd3b3ab5a50dc4191d5caed +Subproject commit 2d4284a0b79c400fd488145e84eb505e0f30f561