udp: add multisend code (sendmmsg)

This commit is contained in:
Jaroslav Kysela 2015-02-20 22:15:46 +01:00
parent fd1bc1c5f7
commit d563dc9127
3 changed files with 144 additions and 0 deletions

12
configure vendored
View file

@ -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)

117
src/udp.c
View file

@ -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;
}

View file

@ -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_ */