diff options
author | Lennart Poettering <lennart@poettering.net> | 2012-01-14 01:53:20 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2012-01-14 01:54:33 +0100 |
commit | 0dad12c190b7493955cd60d2a1625199b1709f69 (patch) | |
tree | 607e747209911ae62a71a23bbc5cb71a6e492580 /src/journal/journal-send.c | |
parent | f5e04665ebf7124f3ea17dcf258793ed73a95fe1 (diff) |
journal: if the data to be sent is larger than the maximum datagram size resort to passing a temporary fd over native protocol
Diffstat (limited to 'src/journal/journal-send.c')
-rw-r--r-- | src/journal/journal-send.c | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index d51aec9690..03bd170728 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -23,6 +23,8 @@ #include <sys/un.h> #include <errno.h> #include <stddef.h> +#include <unistd.h> +#include <fcntl.h> #include "sd-journal.h" #include "util.h" @@ -132,12 +134,19 @@ fail: } _public_ int sd_journal_sendv(const struct iovec *iov, int n) { - int fd; + int fd, buffer_fd; struct iovec *w; uint64_t *l; int i, j = 0; struct msghdr mh; struct sockaddr_un sa; + char path[] = "/tmp/journal.XXXXXX"; + ssize_t k; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control; + struct cmsghdr *cmsg; if (!iov || n <= 0) return -EINVAL; @@ -203,7 +212,51 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { mh.msg_iov = w; mh.msg_iovlen = j; - if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0) + k = sendmsg(fd, &mh, MSG_NOSIGNAL); + if (k >= 0) + return 0; + + if (errno != EMSGSIZE) + return -errno; + + /* Message doesn't fit... Let's dump the data in a temporary + * file and just pass a file descriptor of it to the other + * side */ + + buffer_fd = mkostemp(path, O_CLOEXEC|O_RDWR); + if (buffer_fd < 0) + return -errno; + + if (unlink(path) < 0) { + close_nointr_nofail(buffer_fd); + return -errno; + } + + n = writev(buffer_fd, w, j); + if (n < 0) { + close_nointr_nofail(buffer_fd); + return -errno; + } + + mh.msg_iov = NULL; + mh.msg_iovlen = 0; + + zero(control); + mh.msg_control = &control; + mh.msg_controllen = sizeof(control); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + k = sendmsg(fd, &mh, MSG_NOSIGNAL); + close_nointr_nofail(buffer_fd); + + if (k < 0) return -errno; return 0; |