]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
udp: add multisend code (sendmmsg)
authorJaroslav Kysela <perex@perex.cz>
Fri, 20 Feb 2015 21:15:46 +0000 (22:15 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 11 Mar 2015 20:41:12 +0000 (21:41 +0100)
configure
src/udp.c
src/udp.h

index f72837245f8e59ad13f5bfd080e35b94d708f516..c6889eca91b015c033af5c1786a694d6877644fb 100755 (executable)
--- a/configure
+++ b/configure
@@ -174,6 +174,18 @@ int test(void)
 }
 '
 
+check_cc_snippet sendmmsg '
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <sys/socket.h>
+#define TEST test
+int test(void)
+{
+  sendmmsg(0, NULL, 0, 0);
+  return 0;
+}
+'
+
 check_cc_snippet libiconv '
 #include <iconv.h>
 int test(void)
index dd2498ff3a6d9a6a4228bf8a694b18bdb9cf9197..0732f7c16fc82b394c1469e62b8d1561e6dc1915 100644 (file)
--- a/src/udp.c
+++ b/src/udp.c
@@ -600,3 +600,120 @@ udp_multirecv_read( udp_multirecv_t *um, int fd, int packets,
   }
   return n;
 }
+
+/*
+ * UDP multi packet send support
+ */
+
+#if !defined (CONFIG_SENDMMSG) && defined(__linux__)
+/* define the syscall - works only for linux */
+#include <linux/unistd.h>
+#ifdef __NR_sendmmsg
+
+int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
+             unsigned int flags);
+
+int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
+             unsigned int flags)
+{
+  return syscall(__NR_sendmmsg, sockfd, msgvec, vlen, flags);
+}
+
+#define CONFIG_RECVMMSG
+
+#endif
+#endif
+
+static inline int
+sendmmsg_i(int sockfd, struct mmsghdr *msgvec,
+           unsigned int vlen, unsigned int flags)
+{
+  ssize_t r;
+  unsigned int i;
+
+  for (i = 0; i < vlen; i++) {
+    r = sendmsg(sockfd, &msgvec->msg_hdr, flags);
+    if (r < 0)
+      return (i > 0) ? i : r;
+    msgvec->msg_len = r;
+    msgvec++;
+  }
+  return i;
+}
+
+#ifndef CONFIG_SENDMMSG
+
+int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
+             unsigned int flags);
+
+int
+sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen,
+         unsigned int flags)
+{
+  return recvmmsg_i(sockfd, msgvec, vlen, flags);
+}
+
+#endif
+
+void
+udp_multisend_init( udp_multisend_t *um, int packets, int psize,
+                    struct iovec **iovec )
+{
+  int i;
+
+  assert(um);
+  um->um_psize   = psize;
+  um->um_packets = packets;
+  um->um_data    = malloc(packets * psize);
+  um->um_iovec   = malloc(packets * sizeof(struct iovec));
+  um->um_msg     = calloc(packets,  sizeof(struct mmsghdr));
+  for (i = 0; i < packets; i++) {
+    ((struct mmsghdr *)um->um_msg)[i].msg_hdr.msg_iov    = &um->um_iovec[i];
+    ((struct mmsghdr *)um->um_msg)[i].msg_hdr.msg_iovlen = 1;
+    um->um_iovec[i].iov_base  = um->um_data + i * psize;
+    um->um_iovec[i].iov_len   = psize;
+  }
+  *iovec = um->um_iovec;
+}
+
+void
+udp_multisend_free( udp_multisend_t *um )
+{
+  if (um == NULL)
+    return;
+  free(um->um_msg);    um->um_msg   = NULL;
+  free(um->um_iovec);  um->um_iovec = NULL;
+  free(um->um_data);   um->um_data  = NULL;
+  um->um_psize   = 0;
+  um->um_packets = 0;
+}
+
+int
+udp_multisend_send( udp_multisend_t *um, int fd, int packets )
+{
+  static char use_emul = 0;
+  int n, i;
+  if (um == NULL) {
+    errno = EINVAL;
+    return -1;
+  }
+  if (packets > um->um_packets)
+    packets = um->um_packets;
+  for (i = 0; i < packets; i++)
+    ((struct mmsghdr *)um->um_msg)[i].msg_len = um->um_iovec[i].iov_len;
+  if (!use_emul) {
+    n = sendmmsg(fd, (struct mmsghdr *)um->um_msg, packets, MSG_DONTWAIT);
+  } else {
+    n = -1;
+    errno = ENOSYS;
+  }
+  if (n < 0 && errno == ENOSYS) {
+    use_emul = 1;
+    n = sendmmsg_i(fd, (struct mmsghdr *)um->um_msg, packets, MSG_DONTWAIT);
+  }
+  if (n > 0) {
+    for (i = 0; i < n; i++)
+      um->um_iovec[i].iov_len = ((struct mmsghdr *)um->um_msg)[i].msg_len;
+  }
+  return n;
+}
index be6f062ce3c49e0c3c02afcc3ce24b717f3439ab..20a9d216feea1e5f0f7ada17b39b964d938418d2 100644 (file)
--- a/src/udp.h
+++ b/src/udp.h
@@ -76,5 +76,20 @@ int
 udp_multirecv_read( udp_multirecv_t *um, int fd, int packets,
                     struct iovec **iovec );
 
+typedef struct udp_multisend {
+  int             um_psize;
+  int             um_packets;
+  uint8_t        *um_data;
+  struct iovec   *um_iovec;
+  struct mmsghdr *um_msg;
+} udp_multisend_t;
+
+void
+udp_multisend_init( udp_multisend_t *um, int packets, int psize,
+                    struct iovec **iovec );
+void
+udp_multisend_free( udp_multisend_t *um );
+int
+udp_multisend_send( udp_multisend_t *um, int fd, int packets );
 
 #endif /* UDP_H_ */