diff options
Diffstat (limited to 'erts')
-rw-r--r-- | erts/emulator/sys/unix/sys_uds.c | 30 | ||||
-rw-r--r-- | erts/emulator/sys/unix/sys_uds.h | 10 |
2 files changed, 36 insertions, 4 deletions
diff --git a/erts/emulator/sys/unix/sys_uds.c b/erts/emulator/sys/unix/sys_uds.c index 3b63d05cf6..daebcb307b 100644 --- a/erts/emulator/sys/unix/sys_uds.c +++ b/erts/emulator/sys/unix/sys_uds.c @@ -18,7 +18,6 @@ * %CopyrightEnd% */ - #include "sys_uds.h" int @@ -89,12 +88,32 @@ sys_uds_writev(int fd, struct iovec *iov, size_t iov_len, struct msghdr msg; struct cmsghdr *cmsg = NULL; - int res; + int res, i; /* initialize socket message */ memset(&msg, 0, sizeof(struct msghdr)); - msg.msg_iov = iov; - msg.msg_iovlen = iov_len; + + /* We flatten the iov if it is too long */ + if (iov_len > MAXIOV) { + int size = 0; + char *buff; + for (i = 0; i < iov_len; i++) + size += iov[i].iov_len; + buff = malloc(size); + + for (i = 0; i < iov_len; i++) { + memcpy(buff, iov[i].iov_base, iov[i].iov_len); + buff += iov[i].iov_len; + } + + iov[0].iov_base = buff - size; + iov[0].iov_len = size; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + } else { + msg.msg_iov = iov; + msg.msg_iovlen = iov_len; + } /* initialize the ancillary data */ msg.msg_control = calloc(1, CMSG_SPACE(sizeof(int) * fd_count)); @@ -110,6 +129,9 @@ sys_uds_writev(int fd, struct iovec *iov, size_t iov_len, res = sendmsg(fd, &msg, flags); + if (iov_len > MAXIOV) + free(iov[0].iov_base); + free(msg.msg_control); return res; diff --git a/erts/emulator/sys/unix/sys_uds.h b/erts/emulator/sys/unix/sys_uds.h index 7ff58b17dd..844a2804d8 100644 --- a/erts/emulator/sys/unix/sys_uds.h +++ b/erts/emulator/sys/unix/sys_uds.h @@ -29,10 +29,20 @@ #define _XOPEN_SOURCE 500 #endif +#include <limits.h> + #include <sys/types.h> #include <sys/socket.h> #include <sys/uio.h> +#if defined IOV_MAX +#define MAXIOV IOV_MAX +#elif defined UIO_MAXIOV +#define MAXIOV UIO_MAXIOV +#else +#define MAXIOV 16 +#endif + #include "sys.h" int sys_uds_readv(int fd, struct iovec *iov, size_t iov_len, |