add the recvmmsg syscall that allows receiving multiple msghdrs at
authormbuhl <mbuhl@openbsd.org>
Fri, 2 Sep 2022 13:18:06 +0000 (13:18 +0000)
committermbuhl <mbuhl@openbsd.org>
Fri, 2 Sep 2022 13:18:06 +0000 (13:18 +0000)
once. libc, man page, and regress parts to come.
With input from jca@, guenther@, bluhm@.
OK bluhm@

sys/kern/init_sysent.c
sys/kern/syscalls.c
sys/kern/syscalls.master
sys/kern/uipc_syscalls.c
sys/sys/ktrace.h
sys/sys/socket.h
sys/sys/syscall.h
sys/sys/syscallargs.h

index 7de5335..ca0649b 100644 (file)
@@ -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,
index 7d1339f..0749b50 100644 (file)
@@ -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 */
index cf4612e..eaf34df 100644 (file)
@@ -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
                            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); }
index dbd6373..b68e853 100644 (file)
@@ -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)
index 90c8258..d16ce8b 100644 (file)
@@ -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) \
index fe1b8f9..3575882 100644 (file)
@@ -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);
index ce5beab..114853c 100644 (file)
@@ -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.
 /* 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
 
index 244efc7..18c22de 100644 (file)
@@ -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 *);