static int process_socket(int fd) {
        _cleanup_close_ int coredump_fd = -1;
        struct iovec *iovec = NULL;
        size_t n_iovec = 0, n_allocated = 0, i, k;
        const char *context[_CONTEXT_MAX] = {};
        int r;

        assert(fd >= 0);

        log_setup_service();

        log_debug("Processing coredump received on stdin...");

        for (;;) {
                union {
                        struct cmsghdr cmsghdr;
                        uint8_t buf[CMSG_SPACE(sizeof(int))];
                } control = {};
                struct msghdr mh = {
                        .msg_control = &control,
                        .msg_controllen = sizeof(control),
                        .msg_iovlen = 1,
                };
                ssize_t n;
                ssize_t l;

                if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + SUBMIT_COREDUMP_FIELDS)) {
                        r = log_oom();
                        goto finish;
                }

                l = next_datagram_size_fd(fd);
                if (l < 0) {
                        r = log_error_errno(l, "Failed to determine datagram size to read: %m");
                        goto finish;
                }

                assert(l >= 0);

                iovec[n_iovec].iov_len = l;
                iovec[n_iovec].iov_base = malloc(l + 1);
                if (!iovec[n_iovec].iov_base) {
                        r = log_oom();
                        goto finish;
                }

                mh.msg_iov = iovec + n_iovec;

                n = recvmsg(fd, &mh, MSG_CMSG_CLOEXEC);
                if (n < 0)  {
                        free(iovec[n_iovec].iov_base);
                        r = log_error_errno(errno, "Failed to receive datagram: %m");
                        goto finish;
                }

                if (n == 0) {
                        struct cmsghdr *cmsg, *found = NULL;
                        /* The final zero-length datagram carries the file descriptor and tells us that we're done. */

                        free(iovec[n_iovec].iov_base);

                        CMSG_FOREACH(cmsg, &mh) {
                                if (cmsg->cmsg_level == SOL_SOCKET &&
                                    cmsg->cmsg_type == SCM_RIGHTS &&
                                    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
                                        assert(!found);
                                        found = cmsg;
                                }
                        }

                        if (!found) {
                                log_error("Coredump file descriptor missing.");
                                r = -EBADMSG;
                                goto finish;
                        }

                        assert(coredump_fd < 0);
                        coredump_fd = *(int*) CMSG_DATA(found);
                        break;
                }

                /* Add trailing NUL byte, in case these are strings */
                ((char*) iovec[n_iovec].iov_base)[n] = 0;
                iovec[n_iovec].iov_len = (size_t) n;

                cmsg_close_all(&mh);
                map_context_fields(iovec + n_iovec, context);
                n_iovec++;
        }

        if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec + SUBMIT_COREDUMP_FIELDS)) {
                r = log_oom();
                goto finish;
        }

        /* Make sure we got all data we really need */
        assert(context[CONTEXT_PID]);
        assert(context[CONTEXT_UID]);
        assert(context[CONTEXT_GID]);
        assert(context[CONTEXT_SIGNAL]);
        assert(context[CONTEXT_TIMESTAMP]);
        assert(context[CONTEXT_RLIMIT]);
        assert(context[CONTEXT_HOSTNAME]);
        assert(context[CONTEXT_COMM]);
        assert(coredump_fd >= 0);

        /* Small quirk: the journal fields contain the timestamp padded with six zeroes, so that the kernel-supplied 1s
         * granularity timestamps becomes 1µs granularity, i.e. the granularity systemd usually operates in. Since we
         * are reconstructing the original kernel context, we chop this off again, here. */
        k = strlen(context[CONTEXT_TIMESTAMP]);
        if (k > 6)
                context[CONTEXT_TIMESTAMP] = strndupa(context[CONTEXT_TIMESTAMP], k - 6);

        r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd);

finish:
        for (i = 0; i < n_iovec; i++)
                free(iovec[i].iov_base);
        free(iovec);

        return r;
}