Does FreeBSD have sendmmsg or recvmmsg system calls?

Boris Astardzhiev boris.astardzhiev at gmail.com
Wed Jan 27 10:14:05 UTC 2016


Hello,

I've made a few changes in the patch as recommended here starting with
the switch to ppoll(). I have a question since it's not quite clear to me
as written
in the manpage. Is it possible that ppoll() doesn't return an error and yet
revents
have set either POLLERR or POLLHUP or POLLNVAL?

See patch and comments are again welcomed.


On Wed, Jan 27, 2016 at 6:07 AM, Kevin Oberman <rkoberman at gmail.com> wrote:

> Since this has become a debate on programming style, it seem appropriate
> to mention that Edward Yourdan passed away last Tuesday. For those too
> young to recognize the name, he was the developer of modern structured
> programming. He did recognize the style rules are important, but not
> iron-clad.
>
> Kevin Oberman, Part time kid herder and retired Network Engineer
> E-mail: rkoberman at gmail.com
> PGP Fingerprint: D03FB98AFA78E3B78C1694B318AB39EF1B055683
>
> On Tue, Jan 26, 2016 at 7:04 PM, Bruce Evans <brde at optusnet.com.au> wrote:
>
>> On Wed, 27 Jan 2016, Gary Jennejohn wrote:
>>
>> On Tue, 26 Jan 2016 17:46:52 -0500 (EST)
>>> Daniel Eischen <deischen at freebsd.org> wrote:
>>>
>>> On Tue, 26 Jan 2016, Gary Jennejohn wrote:
>>>>
>>>> On Tue, 26 Jan 2016 09:06:39 -0800
>>>>> Luigi Rizzo <rizzo at iet.unipi.it> wrote:
>>>>>
>>>>> On Tue, Jan 26, 2016 at 5:40 AM, Konstantin Belousov
>>>>>> <kostikbel at gmail.com> wrote:
>>>>>>
>>>>>>> On Mon, Jan 25, 2016 at 11:22:13AM +0200, Boris Astardzhiev wrote:
>>>>>>>
>>>>>>>> +ssize_t
>>>>>>>> +recvmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen,
>>>>>>>> int flags,
>>>>>>>> +    const struct timespec *__restrict timeout)
>>>>>>>> +{
>>>>>>>> +     size_t i, rcvd;
>>>>>>>> +     ssize_t ret;
>>>>>>>> +
>>>>>>>> +     if (timeout != NULL) {
>>>>>>>> +             fd_set fds;
>>>>>>>> +             int res;
>>>>>>>>
>>>>>>> Please move all local definitions to the beginning of the function.
>>>>>>>
>>>>>>
>>>>>> This style recommendation was from 30 years ago and is
>>>>>> bad programming practice, as it tends to complicate analysis
>>>>>> for the human and increase the chance of improper usage of
>>>>>> variables.
>>>>>>
>>>>>> We should move away from this for new code.
>>>>>>
>>>>>
>>>>> Really?  I personally find having all variables grouped together
>>>>> much easier to understand.  Stumbling across declarations in the
>>>>> middle of the code in a for-loop, for example, takes me by surprise.
>>>>>
>>>>
>> +1
>>
>> I used to program in a strict version of the "new" style 25-30 years
>> ago, but learned better.  In the strict version, every variable must
>> have minimal scope, so squillions of inner blocks are needed to limit
>> the scopes.  Some deeply nested of course.  This is a good obfuscation.
>> It even breaks -Wshadow by letting you have unrelated variables named
>> 'i' that don't shadow each other because their scope is limited.  Such
>> variables are good in separate functions but not in the same function.
>> Understanding the code to see that the variables are actually unrelated
>> requires counting more braces than usual.  If you don't do this
>> strictly then you get a random style with some variables declared at
>> the top and some in inner blocks for mostly historical reasons.  A
>> strict style with all of the variables at the top is much easier to
>> write and read.
>>
>> I also greatly dislike initializing variables in their declarations.
>>>>>
>>>>> Maybe I'm just old fashioned since I have been writing C-code for
>>>>> more than 30 years.
>>>>>
>>>>
>>>> +1
>>>>
>>>> Probably should be discouraged, but allowed on a case-by-case
>>>> basis.  One could argue that if you need to declaration blocks
>>>> in the middle of code, then that code is too complex and should
>>>> be broken out into a separate function.
>>>>
>>>
>>> Right.
>>>
>>
>> Lots of inner blocks are good for both making simple code look complex
>> and making it easier to write the complex code in the same function,
>> at least if you use a tiny indentation so that you can have 40 levels
>> of indentation without needing a 500-column terminal.
>>
>> And code like this
>>>
>>> int func(void)
>>> {
>>>  int baz, zot;
>>>  [some more code]
>>>  if (zot < 5)
>>>  {
>>>    int baz = 3;
>>>    [more code]
>>>  }
>>>  [some more code]
>>> }
>>>
>>> is even worse.  The compiler (clang) seems to consider this to
>>> merely be a reinitialization of baz, but a human might be confused.
>>>
>>
>> No, that is a different baz, and is warned about by Wshadow.
>>
>> Something like for (int i = 0; i < 2; i++) is IMHO OK.
>>>
>>
>> Except it is C++ style which is so forbidden that style(9) doesn't
>> know that it needs a rule to forbid it.
>>
>> The worst is C++ style that doesn't limit the scope  -- a bunch of
>> variables at the top and then somewhere in the middle of the function
>> another variable is needed and it is declared at top level of the
>> function scope.  I sometimes do this when in a hurry.  The strict
>> K&R-C90 style requires opening an inner block to do little more than
>> hold the declaration and then (re)indenting and (re)formatting all
>> the code in the inner block.  The C++ style reduces writability and
>> readability in a different way.  It doesn't cause excessive indentation
>> but it doesn't limit the scope much differently than putting all the
>> declarations at the top.  At least the reader can find the declarations
>> easily when they are at the top.
>>
>> Bruce
>>
>> _______________________________________________
>> freebsd-net at freebsd.org mailing list
>> https://lists.freebsd.org/mailman/listinfo/freebsd-net
>> To unsubscribe, send any mail to "freebsd-net-unsubscribe at freebsd.org"
>>
>
>
-------------- next part --------------
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index b448461..7de8ce3 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -99,11 +99,13 @@ SRCS+=	__getosreldate.c \
 	raise.c \
 	readdir.c \
 	readpassphrase.c \
+	recvmmsg.c \
 	rewinddir.c \
 	scandir.c \
 	seed48.c \
 	seekdir.c \
 	semctl.c \
+	sendmmsg.c \
 	setdomainname.c \
 	sethostname.c \
 	setjmperr.c \
@@ -451,10 +453,12 @@ MLINKS+=rand48.3 _rand48.3 \
 	rand48.3 nrand48.3 \
 	rand48.3 seed48.3 \
 	rand48.3 srand48.3
+MLINKS+=recv.2 recvmmsg.2
 MLINKS+=scandir.3 alphasort.3
 MLINKS+=sem_open.3 sem_close.3 \
 	sem_open.3 sem_unlink.3
 MLINKS+=sem_wait.3 sem_trywait.3
+MLINKS+=send.2 sendmmsg.2
 MLINKS+=setjmp.3 _longjmp.3 \
 	setjmp.3 _setjmp.3 \
 	setjmp.3 longjmp.3 \
diff --git a/lib/libc/gen/recvmmsg.c b/lib/libc/gen/recvmmsg.c
new file mode 100644
index 0000000..432008f
--- /dev/null
+++ b/lib/libc/gen/recvmmsg.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016 Boris Astardzhiev, Smartcom-Bulgaria AD
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice(s), this list of conditions and the following disclaimer as
+ *    the first lines of this file unmodified other than the possible
+ *    addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice(s), this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/stddef.h>
+#include "libc_private.h"
+
+#define POLLMASK (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)
+#define EPOLLMASK (POLLERR | POLLHUP | POLLNVAL)
+
+ssize_t
+recvmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags,
+    const struct timespec *__restrict timeout)
+{
+	struct pollfd pfd[1];
+	size_t i, rcvd;
+	ssize_t ret;
+	int res;
+
+	if (timeout != NULL) {
+		pfd[0].fd = s;
+		pfd[0].events = POLLMASK;
+		pfd[0].revents = 0;
+		res = ppoll(&pfd[0], 1, timeout, NULL);
+		if (res == -1 || res == 0)
+			return (res);
+		if (pfd[0].revents & EPOLLMASK ||
+		    (pfd[0].revents & POLLMASK) == 0)
+			return (-1);
+	}
+
+	ret = __sys_recvmsg(s, &msgvec[0].msg_hdr, flags);
+	if (ret == -1)
+		return (ret);
+
+	/* Turn on DONTWAIT if WAITFORONE is set. */
+	if (flags & MSG_WAITFORONE)
+		flags |= MSG_DONTWAIT;
+
+	rcvd = 1;
+	for (i = rcvd; i < vlen; i++, rcvd++) {
+		ret = __sys_recvmsg(s, &msgvec[i].msg_hdr, flags);
+		if (ret == -1) {
+			/* We have received messages. Let caller know. */
+			return (rcvd);
+		}
+
+		/* Save received bytes */
+		msgvec[i].msg_len = ret;
+	}
+
+	return (rcvd);
+}
+
+#undef POLLMASK
+#undef EPOLLMASK
diff --git a/lib/libc/gen/sendmmsg.c b/lib/libc/gen/sendmmsg.c
new file mode 100644
index 0000000..3d91ee2
--- /dev/null
+++ b/lib/libc/gen/sendmmsg.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 Boris Astardzhiev, Smartcom-Bulgaria AD
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice(s), this list of conditions and the following disclaimer as
+ *    the first lines of this file unmodified other than the possible
+ *    addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice(s), this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+ssize_t
+sendmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags)
+{
+	size_t i, sent;
+	ssize_t ret;
+
+	sent = 0;
+	for (i = 0; i < vlen; i++, sent++) {
+		ret = __sys_sendmsg(s, &msgvec[i].msg_hdr, flags);
+		if (ret == -1) {
+			if (sent != 0) {
+				/* We have sent messages. Let caller know. */
+				return (sent);
+			}
+			return (ret);
+		}
+
+		/* Save sent bytes */
+		msgvec[i].msg_len = ret;
+	}
+
+	return (sent);
+}
diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h
index 739d7b1..c95829e 100644
--- a/lib/libc/include/namespace.h
+++ b/lib/libc/include/namespace.h
@@ -208,6 +208,7 @@
 #define		readv				_readv
 #define		recvfrom			_recvfrom
 #define		recvmsg				_recvmsg
+#define		recvmmsg			_recvmmsg
 #define		select				_select
 #define		sem_close			_sem_close
 #define		sem_destroy			_sem_destroy
@@ -220,6 +221,7 @@
 #define		sem_unlink			_sem_unlink
 #define		sem_wait			_sem_wait
 #define		sendmsg				_sendmsg
+#define		sendmmsg			_sendmmsg
 #define		sendto				_sendto
 #define		setsockopt			_setsockopt
 /*#define		sigaction			_sigaction*/
diff --git a/lib/libc/include/un-namespace.h b/lib/libc/include/un-namespace.h
index f31fa7a..0233348 100644
--- a/lib/libc/include/un-namespace.h
+++ b/lib/libc/include/un-namespace.h
@@ -189,6 +189,7 @@
 #undef		readv
 #undef		recvfrom
 #undef		recvmsg
+#undef		recvmmsg
 #undef		select
 #undef		sem_close
 #undef		sem_destroy
@@ -201,6 +202,7 @@
 #undef		sem_unlink
 #undef		sem_wait
 #undef		sendmsg
+#undef		sendmmsg
 #undef		sendto
 #undef		setsockopt
 #undef		sigaction
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index 7b3257c..dc2ed0e 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -399,6 +399,8 @@ FBSD_1.4 {
 	utimensat;
 	numa_setaffinity;
 	numa_getaffinity;
+	sendmmsg;
+	recvmmsg;
 };
 
 FBSDprivate_1.0 {
diff --git a/lib/libc/sys/recv.2 b/lib/libc/sys/recv.2
index 326e7ff..cb54622 100644
--- a/lib/libc/sys/recv.2
+++ b/lib/libc/sys/recv.2
@@ -34,8 +34,9 @@
 .Sh NAME
 .Nm recv ,
 .Nm recvfrom ,
-.Nm recvmsg
-.Nd receive a message from a socket
+.Nm recvmsg ,
+.Nm recvmmsg
+.Nd receive message(s) from a socket
 .Sh LIBRARY
 .Lb libc
 .Sh SYNOPSIS
@@ -47,11 +48,15 @@
 .Fn recvfrom "int s" "void *buf" "size_t len" "int flags" "struct sockaddr * restrict from" "socklen_t * restrict fromlen"
 .Ft ssize_t
 .Fn recvmsg "int s" "struct msghdr *msg" "int flags"
+.Ft ssize_t
+.Fn recvmmsg "int s" "struct mmsghdr * restrict msgvec" "size_t vlen" "int flags" "const struct timespec * restrict timeout"
 .Sh DESCRIPTION
 The
 .Fn recvfrom
 and
 .Fn recvmsg
+and
+.Fn recvmmsg
 system calls
 are used to receive messages from a socket,
 and may be used to receive data on a socket whether or not
@@ -84,8 +89,29 @@ null pointer passed as its
 .Fa from
 argument.
 .Pp
-All three routines return the length of the message on successful
-completion.
+The
+.Fn recvmmsg
+function is used to receive multiple
+messages at a call.
+Their number is supplied by
+.Fa vlen .
+The messages are placed in the
+.Fa msgvec
+vector after reception.
+The size of each received message is placed in the
+.Fa msg_len
+field of each element of the vector.
+If
+.Fa timeout
+is NULL the call will normally block.
+Otherwise it will wait for data for the specified amount of time.
+If the timeout expires and there is no data received a value of 0 is returned.
+ppoll(2) is used for the implementation of the timeout mechanism.
+.Pp
+The first three routines return the length of the message on successful
+completion whereas
+.Fn recvmmsg
+returns the number of received messages.
 If a message is too long to fit in the supplied buffer,
 excess bytes may be discarded depending on the type of socket
 the message is received from (see
@@ -100,7 +126,9 @@ in which case the value
 .Va errno
 is set to
 .Er EAGAIN .
-The receive calls normally return any data available,
+The receive calls except
+.Fn recvmmsg
+normally return any data available,
 up to the requested amount,
 rather than waiting for receipt of the full amount requested;
 this behavior is affected by the socket-level options
@@ -127,6 +155,9 @@ one or more of the values:
 .It Dv MSG_WAITALL Ta wait for full request or error
 .It Dv MSG_DONTWAIT Ta do not block
 .It Dv MSG_CMSG_CLOEXEC Ta set received fds close-on-exec
+.It Dv MSG_WAITFORONE Ta do not block after receiving the first message
+(relevant only for
+.Fn recvmmsg )
 .El
 .Pp
 The
@@ -158,6 +189,11 @@ is set to
 This flag is not available in strict
 .Tn ANSI
 or C99 compilation mode.
+The
+.Dv MSG_WAITFORONE
+flag sets MSG_DONTWAIT after the first message has been received.
+This flag is only relevant for
+.Fn recvmmsg .
 .Pp
 The
 .Fn recvmsg
@@ -290,9 +326,33 @@ control data were discarded due to lack of space in the buffer
 for ancillary data.
 .Dv MSG_OOB
 is returned to indicate that expedited or out-of-band data were received.
+.Pp
+The
+.Fn recvmmsg
+system call uses the
+.Fa mmsghdr
+structure. Its form is as follows, as defined in
+.In sys/socket.h :
+.Bd -literal
+struct mmsghdr {
+	struct msghdr	 msg_hdr;	/* message header */
+	ssize_t		 msg_len;	/* message length */
+};
+.Ed
+.Pp
+For
+.Fa msg_hdr
+see above. On data reception the
+.Fa msg_len
+field is updated to the length of the received message.
+On data transmission it is updated to the number of characters sent.
 .Sh RETURN VALUES
-These calls return the number of bytes received, or -1
-if an error occurred.
+These calls except
+.Fn recvmmsg
+return the number of bytes received.
+.Fn recvmmsg
+returns the number of messages received.
+A value of -1 is returned if an error occurred.
 .Sh ERRORS
 The calls fail if:
 .Bl -tag -width Er
diff --git a/lib/libc/sys/send.2 b/lib/libc/sys/send.2
index 8fa2c64..9810ace 100644
--- a/lib/libc/sys/send.2
+++ b/lib/libc/sys/send.2
@@ -34,8 +34,9 @@
 .Sh NAME
 .Nm send ,
 .Nm sendto ,
-.Nm sendmsg
-.Nd send a message from a socket
+.Nm sendmsg ,
+.Nm sendmmsg
+.Nd send message(s) from a socket
 .Sh LIBRARY
 .Lb libc
 .Sh SYNOPSIS
@@ -47,6 +48,8 @@
 .Fn sendto "int s" "const void *msg" "size_t len" "int flags" "const struct sockaddr *to" "socklen_t tolen"
 .Ft ssize_t
 .Fn sendmsg "int s" "const struct msghdr *msg" "int flags"
+.Ft ssize_t
+.Fn sendmmsg "int s" "struct mmsghdr * restrict msgvec" "size_t vlen" "int flags"
 .Sh DESCRIPTION
 The
 .Fn send
@@ -55,8 +58,11 @@ and
 .Fn sendto
 and
 .Fn sendmsg
+and
+.Fn sendmmsg
 system calls
-are used to transmit a message to another socket.
+are used to transmit one or multiple messages (with the latter call) to
+another socket.
 The
 .Fn send
 function
@@ -66,6 +72,8 @@ state, while
 .Fn sendto
 and
 .Fn sendmsg
+and
+.Fn sendmmsg
 may be used at any time.
 .Pp
 The address of the target is given by
@@ -81,6 +89,18 @@ underlying protocol, the error
 is returned, and
 the message is not transmitted.
 .Pp
+The
+.Fn sendmmsg
+function sends multiple messages at a call.
+They are given by the
+.Fa msgvec
+vector along with
+.Fa vlen
+specifying its size.
+The number of characters sent per each message is placed in the
+.Fa msg_len
+field of each element of the vector after transmission.
+.Pp
 No indication of failure to deliver is implicit in a
 .Fn send .
 Locally detected errors are indicated by a return value of -1.
@@ -138,10 +158,16 @@ See
 .Xr recv 2
 for a description of the
 .Fa msghdr
+structure and the
+.Fa mmsghdr
 structure.
 .Sh RETURN VALUES
-The call returns the number of characters sent, or -1
-if an error occurred.
+All calls except
+.Fn sendmmsg
+return the number of characters sent. The
+.Fn sendmmsg
+call returns the number of messages sent.
+If an error occurred a value of -1 is returned.
 .Sh ERRORS
 The
 .Fn send
@@ -149,6 +175,8 @@ function and
 .Fn sendto
 and
 .Fn sendmsg
+and
+.Fn sendmmsg
 system calls
 fail if:
 .Bl -tag -width Er
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index 18e2de1..5da286e 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -431,6 +431,7 @@ struct msghdr {
 #define	MSG_NBIO	0x4000		/* FIONBIO mode, used by fifofs */
 #define	MSG_COMPAT      0x8000		/* used in sendit() */
 #define	MSG_CMSG_CLOEXEC 0x40000	/* make received fds close-on-exec */
+#define MSG_WAITFORONE	0x80000		/* for recvmmsg() */
 #endif
 #ifdef _KERNEL
 #define	MSG_SOCALLBCK   0x10000		/* for use by socket callbacks - soreceive (TCP) */
@@ -595,6 +596,16 @@ struct sf_hdtr {
 #endif /* _KERNEL */
 #endif /* __BSD_VISIBLE */
 
+#ifdef __BSD_VISIBLE
+/*
+ * Send/recvmmsg specific structure(s)
+ */
+struct mmsghdr {
+	struct msghdr	msg_hdr;		/* message header */
+	ssize_t		msg_len;		/* message length */
+};
+#endif /* __BSD_VISIBLE */
+
 #ifndef	_KERNEL
 
 #include <sys/cdefs.h>
@@ -615,12 +626,18 @@ int	listen(int, int);
 ssize_t	recv(int, void *, size_t, int);
 ssize_t	recvfrom(int, void *, size_t, int, struct sockaddr * __restrict, socklen_t * __restrict);
 ssize_t	recvmsg(int, struct msghdr *, int);
+#if __BSD_VISIBLE
+struct timespec;
+ssize_t	recvmmsg(int, struct mmsghdr * __restrict, size_t, int,
+    const struct timespec * __restrict);
+#endif
 ssize_t	send(int, const void *, size_t, int);
 ssize_t	sendto(int, const void *,
 	    size_t, int, const struct sockaddr *, socklen_t);
 ssize_t	sendmsg(int, const struct msghdr *, int);
 #if __BSD_VISIBLE
 int	sendfile(int, int, off_t, size_t, struct sf_hdtr *, off_t *, int);
+ssize_t	sendmmsg(int, struct mmsghdr * __restrict, size_t, int);
 int	setfib(int);
 #endif
 int	setsockopt(int, int, int, const void *, socklen_t);


More information about the freebsd-threads mailing list