From d563dc9127185617944504493f95bcb1ca3eaef0 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 20 Feb 2015 22:15:46 +0100 Subject: [PATCH] udp: add multisend code (sendmmsg) --- configure | 12 ++++++ src/udp.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/udp.h | 15 +++++++ 3 files changed, 144 insertions(+) diff --git a/configure b/configure index f7283724..c6889eca 100755 --- a/configure +++ b/configure @@ -174,6 +174,18 @@ int test(void) } ' +check_cc_snippet sendmmsg ' +#define _GNU_SOURCE +#include +#include +#define TEST test +int test(void) +{ + sendmmsg(0, NULL, 0, 0); + return 0; +} +' + check_cc_snippet libiconv ' #include int test(void) diff --git a/src/udp.c b/src/udp.c index dd2498ff..0732f7c1 100644 --- 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 +#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; +} diff --git a/src/udp.h b/src/udp.h index be6f062c..20a9d216 100644 --- 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_ */