typedef unsigned short int sa_family_t;
typedef __socklen_t socklen_t;
+struct timespec;
struct sockaddr {
sa_family_t sa_family;
MSG_PEEK,
MSG_TRUNC,
MSG_WAITALL,
- MSG_DONTWAIT
+ MSG_DONTWAIT,
+ MSG_WAITFORONE
};
enum {
ssize_t send(int, const void *, size_t, int);
ssize_t sendmsg(int, const struct msghdr *, int);
int sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
+int recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *);
ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *,
socklen_t);
int setsockopt(int, int, int, const void *, socklen_t);
}
#endif
#endif
+\f
+#ifndef _WIN32 /* Avoid using recvmsg on Windows entirely. */
+static int
+emulate_recvmmsg(int fd, struct mmsghdr *msgs, unsigned int n,
+ int flags, struct timespec *timeout OVS_UNUSED)
+{
+ ovs_assert(!timeout); /* XXX not emulated */
+
+ bool waitforone = flags & MSG_WAITFORONE;
+ flags &= ~MSG_WAITFORONE;
+
+ for (unsigned int i = 0; i < n; i++) {
+ ssize_t retval = recvmsg(fd, &msgs[i].msg_hdr, flags);
+ if (retval < 0) {
+ return i ? i : retval;
+ }
+ msgs[i].msg_len = retval;
+
+ if (waitforone) {
+ flags |= MSG_DONTWAIT;
+ }
+ }
+ return n;
+}
+
+#ifndef HAVE_SENDMMSG
+int
+recvmmsg(int fd, struct mmsghdr *msgs, unsigned int n,
+ int flags, struct timespec *timeout)
+{
+ return emulate_recvmmsg(fd, msgs, n, flags, timeout);
+}
+#else
+/* recvmmsg was redefined in lib/socket-util.c, should undef recvmmsg here
+ * to avoid recursion */
+#undef recvmmsg
+int
+wrap_recvmmsg(int fd, struct mmsghdr *msgs, unsigned int n,
+ int flags, struct timespec *timeout)
+{
+ ovs_assert(!timeout); /* XXX not emulated */
+
+ static bool recvmmsg_broken = false;
+ if (!recvmmsg_broken) {
+ int save_errno = errno;
+ int retval = recvmmsg(fd, msgs, n, flags, timeout);
+ if (retval >= 0 || errno != ENOSYS) {
+ return retval;
+ }
+ recvmmsg_broken = true;
+ errno = save_errno;
+ }
+ return emulate_recvmmsg(fd, msgs, n, flags, timeout);
+}
+#endif
+#endif
const char *bind_path, const char *connect_path);
int get_unix_name_len(const struct sockaddr_un *sun, socklen_t sun_len);
-/* Universal sendmmsg support.
+/* Universal sendmmsg and recvmmsg support.
*
- * Some platforms, such as new enough Linux and FreeBSD, support sendmmsg, but
- * other platforms (or older ones) do not. We add the following infrastructure
- * to allow all code to use sendmmsg, regardless of platform support:
+ * Some platforms, such as new enough Linux and FreeBSD, support sendmmsg and
+ * recvmmsg, but other platforms (or older ones) do not. We add the following
+ * infrastructure to allow all code to use sendmmsg and recvmmsg, regardless of
+ * platform support:
*
- * - For platforms that lack sendmmsg entirely, we emulate it.
+ * - For platforms that lack these functions entirely, we emulate them.
*
- * - Some platforms have sendmmsg() in the C library but not in the kernel.
- * For example, this is true if a Linux system has a newer glibc with an
- * old kernel. To compensate, even if sendmmsg() appears to be available,
- * we still wrap it with a handler that uses our emulation if sendmmsg()
- * returns ENOSYS.
+ * - Some platforms have sendmmsg() and recvmmsg() in the C library but not in
+ * the kernel. For example, this is true if a Linux system has a newer glibc
+ * with an old kernel. To compensate, even if these functions appear to be
+ * available, we still wrap them with handlers that uses our emulation if the
+ * underlying function returns ENOSYS.
*/
#ifndef HAVE_STRUCT_MMSGHDR_MSG_LEN
struct mmsghdr {
#endif
#ifndef HAVE_SENDMMSG
int sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
+int recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *);
#else
#define sendmmsg wrap_sendmmsg
int wrap_sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
+#define recvmmsg wrap_recvmmsg
+int wrap_recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *);
#endif
/* Helpers for calling ioctl() on an AF_INET socket. */