From: Tulio A M Mendes Date: Sun, 15 Feb 2026 08:14:34 +0000 (-0300) Subject: feat: sendmsg/recvmsg — advanced socket I/O with scatter-gather iovec support X-Git-Url: https://projects.tadryanom.me/docs/static/git-favicon.png?a=commitdiff_plain;h=6767ac5c69975b437fa6eaa442e6c707d03c9162;p=AdrOS.git feat: sendmsg/recvmsg — advanced socket I/O with scatter-gather iovec support --- diff --git a/include/syscall.h b/include/syscall.h index 14b9850..9f6aae0 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -143,6 +143,9 @@ enum { SYSCALL_INOTIFY_INIT = 115, SYSCALL_INOTIFY_ADD_WATCH = 116, SYSCALL_INOTIFY_RM_WATCH = 117, + + SYSCALL_SENDMSG = 118, + SYSCALL_RECVMSG = 119, }; #endif diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 64dbabf..0e03f02 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -4071,6 +4071,73 @@ static inline int sock_fd_get_sid(int fd) { return (int)f->node->inode; } +__attribute__((noinline)) +static int syscall_sendmsg_impl(int sockfd, void* user_msg, int flags) { + int sid = sock_fd_get_sid(sockfd); + if (sid < 0) return -EBADF; + + struct { void* name; uint32_t namelen; void* iov; uint32_t iovlen; + void* control; uint32_t controllen; int mflags; } kmsg; + if (copy_from_user(&kmsg, user_msg, sizeof(kmsg)) < 0) return -EFAULT; + + struct sockaddr_in dest; + int has_dest = 0; + if (kmsg.name && kmsg.namelen >= sizeof(dest)) { + if (copy_from_user(&dest, kmsg.name, sizeof(dest)) < 0) return -EFAULT; + has_dest = 1; + } + + int total = 0; + for (uint32_t i = 0; i < kmsg.iovlen && i < 16; i++) { + struct { void* base; uint32_t len; } kiov; + uint8_t* iov_arr = (uint8_t*)kmsg.iov; + if (copy_from_user(&kiov, &iov_arr[i * sizeof(kiov)], sizeof(kiov)) < 0) + return -EFAULT; + if (kiov.len == 0) continue; + if (!user_range_ok(kiov.base, kiov.len)) return -EFAULT; + int ret; + if (has_dest) + ret = ksocket_sendto(sid, kiov.base, kiov.len, flags, &dest); + else + ret = ksocket_send(sid, kiov.base, kiov.len, flags); + if (ret < 0) return (total > 0) ? total : ret; + total += ret; + } + return total; +} + +__attribute__((noinline)) +static int syscall_recvmsg_impl(int sockfd, void* user_msg, int flags) { + int sid = sock_fd_get_sid(sockfd); + if (sid < 0) return -EBADF; + + struct { void* name; uint32_t namelen; void* iov; uint32_t iovlen; + void* control; uint32_t controllen; int mflags; } kmsg; + if (copy_from_user(&kmsg, user_msg, sizeof(kmsg)) < 0) return -EFAULT; + + int total = 0; + struct sockaddr_in src; + memset(&src, 0, sizeof(src)); + + for (uint32_t i = 0; i < kmsg.iovlen && i < 16; i++) { + struct { void* base; uint32_t len; } kiov; + uint8_t* iov_arr = (uint8_t*)kmsg.iov; + if (copy_from_user(&kiov, &iov_arr[i * sizeof(kiov)], sizeof(kiov)) < 0) + return -EFAULT; + if (kiov.len == 0) continue; + if (!user_range_ok(kiov.base, kiov.len)) return -EFAULT; + int ret = ksocket_recvfrom(sid, kiov.base, kiov.len, flags, &src); + if (ret < 0) return (total > 0) ? total : ret; + total += ret; + if ((uint32_t)ret < kiov.len) break; + } + + if (kmsg.name && kmsg.namelen >= sizeof(src)) + (void)copy_to_user(kmsg.name, &src, sizeof(src)); + + return total; +} + /* Separate function to keep socket locals off syscall_handler's stack frame */ __attribute__((noinline)) static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no) { @@ -4202,6 +4269,18 @@ static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no) return; } + if (syscall_no == SYSCALL_SENDMSG) { + sc_ret(regs) = (uint32_t)syscall_sendmsg_impl( + (int)sc_arg0(regs), (void*)sc_arg1(regs), (int)sc_arg2(regs)); + return; + } + + if (syscall_no == SYSCALL_RECVMSG) { + sc_ret(regs) = (uint32_t)syscall_recvmsg_impl( + (int)sc_arg0(regs), (void*)sc_arg1(regs), (int)sc_arg2(regs)); + return; + } + if (syscall_no == SYSCALL_SETITIMER) { /* setitimer(which, user_new_value, user_old_value) * struct itimerval { uint32_t it_interval; uint32_t it_value; } (ticks) */