From 8945982be22ebdb35731babc914d40f1e79d8d3f Mon Sep 17 00:00:00 2001 From: mbuhl Date: Fri, 2 Sep 2022 13:18:06 +0000 Subject: [PATCH] add the recvmmsg syscall that allows receiving multiple msghdrs at once. libc, man page, and regress parts to come. With input from jca@, guenther@, bluhm@. OK bluhm@ --- sys/kern/init_sysent.c | 8 +-- sys/kern/syscalls.c | 6 +- sys/kern/syscalls.master | 8 ++- sys/kern/uipc_syscalls.c | 136 ++++++++++++++++++++++++++++++++++++++- sys/sys/ktrace.h | 4 +- sys/sys/socket.h | 12 +++- sys/sys/syscall.h | 7 +- sys/sys/syscallargs.h | 11 +++- 8 files changed, 175 insertions(+), 17 deletions(-) diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 7de53351014..ca0649b533a 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init_sysent.c,v 1.243 2022/08/01 14:57:19 deraadt Exp $ */ +/* $OpenBSD: init_sysent.c,v 1.244 2022/09/02 13:18:06 mbuhl Exp $ */ /* * System call switch table. @@ -264,10 +264,10 @@ const struct sysent sysent[] = { sys_unveil }, /* 114 = unveil */ { 2, s(struct sys___realpath_args), 0, sys___realpath }, /* 115 = __realpath */ + { 5, s(struct sys_recvmmsg_args), SY_NOLOCK | 0, + sys_recvmmsg }, /* 116 = recvmmsg */ { 0, 0, 0, - sys_nosys }, /* 116 = obsolete t32_gettimeofday */ - { 0, 0, 0, - sys_nosys }, /* 117 = obsolete t32_getrusage */ + sys_nosys }, /* 117 = unimplemented sendmmsg */ { 5, s(struct sys_getsockopt_args), 0, sys_getsockopt }, /* 118 = getsockopt */ { 3, s(struct sys_thrkill_args), 0, diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 7d1339fad1e..0749b50568d 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: syscalls.c,v 1.241 2022/08/01 14:57:19 deraadt Exp $ */ +/* $OpenBSD: syscalls.c,v 1.242 2022/09/02 13:18:06 mbuhl Exp $ */ /* * System call names. @@ -136,8 +136,8 @@ const char *const syscallnames[] = { "#113 (unimplemented fktrace)", /* 113 = unimplemented fktrace */ "unveil", /* 114 = unveil */ "__realpath", /* 115 = __realpath */ - "#116 (obsolete t32_gettimeofday)", /* 116 = obsolete t32_gettimeofday */ - "#117 (obsolete t32_getrusage)", /* 117 = obsolete t32_getrusage */ + "recvmmsg", /* 116 = recvmmsg */ + "#117 (unimplemented sendmmsg)", /* 117 = unimplemented sendmmsg */ "getsockopt", /* 118 = getsockopt */ "thrkill", /* 119 = thrkill */ "readv", /* 120 = readv */ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index cf4612e067b..eaf34dfabfe 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ -; $OpenBSD: syscalls.master,v 1.229 2022/08/01 14:56:59 deraadt Exp $ +; $OpenBSD: syscalls.master,v 1.230 2022/09/02 13:18:06 mbuhl Exp $ ; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 @@ -244,8 +244,10 @@ const char *permissions); } 115 STD { int sys___realpath(const char *pathname, \ char *resolved); } -116 OBSOL t32_gettimeofday -117 OBSOL t32_getrusage +116 STD NOLOCK { int sys_recvmmsg(int s, struct mmsghdr *mmsg, \ + unsigned int vlen, unsigned int flags, \ + struct timespec *timeout); } +117 UNIMPL sendmmsg 118 STD { int sys_getsockopt(int s, int level, int name, \ void *val, socklen_t *avalsize); } 119 STD { int sys_thrkill(pid_t tid, int signum, void *tcb); } diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index dbd6373285e..b68e8534048 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_syscalls.c,v 1.201 2022/08/14 01:58:28 jsg Exp $ */ +/* $OpenBSD: uipc_syscalls.c,v 1.202 2022/09/02 13:18:06 mbuhl Exp $ */ /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ /* @@ -804,6 +804,140 @@ done: return (error); } +int +sys_recvmmsg(struct proc *p, void *v, register_t *retval) +{ + struct sys_recvmmsg_args /* { + syscallarg(int) s; + syscallarg(struct mmsghdr *) mmsg; + syscallarg(unsigned int) vlen; + syscallarg(unsigned int) flags; + syscallarg(struct timespec *) timeout; + } */ *uap = v; + struct mmsghdr mmsg, *mmsgp; + struct timespec ts, now; + struct iovec aiov[UIO_SMALLIOV], *uiov, *iov = aiov; + struct file *fp; + struct socket *so; + struct timespec *timeout; + size_t iovlen = UIO_SMALLIOV; + register_t retrec; + unsigned int vlen, dgrams; + int error = 0, flags, s; + + s = SCARG(uap, s); + if ((error = getsock(p, s, &fp))) + return (error); + so = (struct socket *)fp->f_data; + + timeout = SCARG(uap, timeout); + if (timeout != NULL) { + error = copyin(timeout, &ts, sizeof(ts)); + if (error) + return error; +#ifdef KTRACE + if (KTRPOINT(p, KTR_STRUCT)) + ktrreltimespec(p, &ts); +#endif + getnanotime(&now); + timespecadd(&now, &ts, &ts); + } + + flags = SCARG(uap, flags); + + /* Arbitrarily capped at 1024 datagrams. */ + vlen = SCARG(uap, vlen); + if (vlen > 1024) + vlen = 1024; + + mmsgp = SCARG(uap, mmsg); + for (dgrams = 0; dgrams < vlen;) { + error = copyin(&mmsgp[dgrams], &mmsg, sizeof(mmsg)); + if (error) + break; + + if (mmsg.msg_hdr.msg_iovlen > IOV_MAX) { + error = EMSGSIZE; + break; + } + + if (mmsg.msg_hdr.msg_iovlen > iovlen) { + if (iov != aiov) + free(iov, M_IOV, iovlen * + sizeof(struct iovec)); + + iovlen = mmsg.msg_hdr.msg_iovlen; + iov = mallocarray(iovlen, sizeof(struct iovec), + M_IOV, M_WAITOK); + } + + if (mmsg.msg_hdr.msg_iovlen > 0) { + error = copyin(mmsg.msg_hdr.msg_iov, iov, + mmsg.msg_hdr.msg_iovlen * sizeof(struct iovec)); + if (error) + break; + } + + uiov = mmsg.msg_hdr.msg_iov; + mmsg.msg_hdr.msg_iov = iov; + mmsg.msg_hdr.msg_flags = flags; + + error = recvit(p, s, &mmsg.msg_hdr, NULL, &retrec); + if (error) { + if (error == EAGAIN && dgrams > 0) + error = 0; + break; + } + + if (dgrams == 0 && flags & MSG_WAITFORONE) { + flags &= ~MSG_WAITFORONE; + flags |= MSG_DONTWAIT; + } + + mmsg.msg_hdr.msg_iov = uiov; + mmsg.msg_len = retrec; +#ifdef KTRACE + if (KTRPOINT(p, KTR_STRUCT)) { + ktrmmsghdr(p, &mmsg); + if (mmsg.msg_hdr.msg_iovlen) + ktriovec(p, iov, mmsg.msg_hdr.msg_iovlen); + } +#endif + + error = copyout(&mmsg, &mmsgp[dgrams], sizeof(mmsg)); + if (error) + break; + + dgrams++; + if (mmsg.msg_hdr.msg_flags & MSG_OOB) + break; + + if (timeout != NULL) { + getnanotime(&now); + timespecsub(&now, &ts, &now); + if (now.tv_sec > 0) + break; + } + } + + if (iov != aiov) + free(iov, M_IOV, iovlen * sizeof(struct iovec)); + + *retval = dgrams; + + /* + * If we succeeded at least once, return 0, hopefully so->so_error + * will catch it next time. + */ + if (error && dgrams > 0) { + so->so_error = error; + error = 0; + } + + FRELE(fp, p); + return (error); +} + int recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp, register_t *retsize) diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h index 90c8258de9c..d16ce8b8982 100644 --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ktrace.h,v 1.41 2022/02/22 17:14:14 deraadt Exp $ */ +/* $OpenBSD: ktrace.h,v 1.42 2022/09/02 13:18:07 mbuhl Exp $ */ /* $NetBSD: ktrace.h,v 1.12 1996/02/04 02:12:29 christos Exp $ */ /* @@ -239,6 +239,8 @@ void ktrstruct(struct proc *, const char *, const void *, size_t); ktrstruct((p), "quota", (s), sizeof(struct dqblk)) #define ktrmsghdr(p, s) \ ktrstruct(p, "msghdr", s, sizeof(struct msghdr)) +#define ktrmmsghdr(p, s) \ + ktrstruct(p, "mmsghdr", s, sizeof(struct mmsghdr)) #define ktriovec(p, s, count) \ ktrstruct(p, "iovec", s, (count) * sizeof(struct iovec)) #define ktrcmsghdr(p, c, len) \ diff --git a/sys/sys/socket.h b/sys/sys/socket.h index fe1b8f954c8..35758827b30 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -1,4 +1,4 @@ -/* $OpenBSD: socket.h,v 1.102 2022/02/22 01:01:02 guenther Exp $ */ +/* $OpenBSD: socket.h,v 1.103 2022/09/02 13:18:07 mbuhl Exp $ */ /* $NetBSD: socket.h,v 1.14 1996/02/09 18:25:36 christos Exp $ */ /* @@ -490,6 +490,13 @@ struct msghdr { int msg_flags; /* flags on received message */ }; +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct timespec; + #define MSG_OOB 0x1 /* process out-of-band data */ #define MSG_PEEK 0x2 /* peek at incoming message */ #define MSG_DONTROUTE 0x4 /* send without using routing tables */ @@ -502,6 +509,7 @@ struct msghdr { #define MSG_MCAST 0x200 /* this message rec'd as multicast */ #define MSG_NOSIGNAL 0x400 /* do not send SIGPIPE */ #define MSG_CMSG_CLOEXEC 0x800 /* set FD_CLOEXEC on received fds */ +#define MSG_WAITFORONE 0x1000 /* nonblocking but wait for one msg */ /* * Header for ancillary data objects in msg_control buffer. @@ -565,6 +573,8 @@ int listen(int, int); ssize_t recv(int, void *, size_t, int); ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); ssize_t recvmsg(int, struct msghdr *, int); +int recvmmsg(int, struct mmsghdr *, unsigned int, unsigned int, + struct timespec *); ssize_t send(int, const void *, size_t, int); ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t); diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index ce5beabe24a..114853c3cae 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.240 2022/08/01 14:57:19 deraadt Exp $ */ +/* $OpenBSD: syscall.h,v 1.241 2022/09/02 13:18:07 mbuhl Exp $ */ /* * System call numbers. @@ -352,8 +352,9 @@ /* syscall: "__realpath" ret: "int" args: "const char *" "char *" */ #define SYS___realpath 115 - /* 116 is obsolete t32_gettimeofday */ - /* 117 is obsolete t32_getrusage */ +/* syscall: "recvmmsg" ret: "int" args: "int" "struct mmsghdr *" "unsigned int" "unsigned int" "struct timespec *" */ +#define SYS_recvmmsg 116 + /* syscall: "getsockopt" ret: "int" args: "int" "int" "int" "void *" "socklen_t *" */ #define SYS_getsockopt 118 diff --git a/sys/sys/syscallargs.h b/sys/sys/syscallargs.h index 244efc75638..18c22debe02 100644 --- a/sys/sys/syscallargs.h +++ b/sys/sys/syscallargs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscallargs.h,v 1.243 2022/08/01 14:57:19 deraadt Exp $ */ +/* $OpenBSD: syscallargs.h,v 1.244 2022/09/02 13:18:07 mbuhl Exp $ */ /* * System call argument lists. @@ -595,6 +595,14 @@ struct sys___realpath_args { syscallarg(char *) resolved; }; +struct sys_recvmmsg_args { + syscallarg(int) s; + syscallarg(struct mmsghdr *) mmsg; + syscallarg(unsigned int) vlen; + syscallarg(unsigned int) flags; + syscallarg(struct timespec *) timeout; +}; + struct sys_getsockopt_args { syscallarg(int) s; syscallarg(int) level; @@ -1302,6 +1310,7 @@ int sys_sigsuspend(struct proc *, void *, register_t *); int sys_sendsyslog(struct proc *, void *, register_t *); int sys_unveil(struct proc *, void *, register_t *); int sys___realpath(struct proc *, void *, register_t *); +int sys_recvmmsg(struct proc *, void *, register_t *); int sys_getsockopt(struct proc *, void *, register_t *); int sys_thrkill(struct proc *, void *, register_t *); int sys_readv(struct proc *, void *, register_t *); -- 2.20.1