xref: /freebsd/lib/libnv/msgio.c (revision 032f0fbbb657405ac6312f7493a95bed7d5cf87a)
136da5199SPawel Jakub Dawidek /*-
25e53a4f9SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
35e53a4f9SPedro F. Giffuni  *
436da5199SPawel Jakub Dawidek  * Copyright (c) 2013 The FreeBSD Foundation
536da5199SPawel Jakub Dawidek  * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
636da5199SPawel Jakub Dawidek  * All rights reserved.
736da5199SPawel Jakub Dawidek  *
836da5199SPawel Jakub Dawidek  * This software was developed by Pawel Jakub Dawidek under sponsorship from
936da5199SPawel Jakub Dawidek  * the FreeBSD Foundation.
1036da5199SPawel Jakub Dawidek  *
1136da5199SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
1236da5199SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
1336da5199SPawel Jakub Dawidek  * are met:
1436da5199SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
1536da5199SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1636da5199SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1736da5199SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1836da5199SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1936da5199SPawel Jakub Dawidek  *
2036da5199SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
2136da5199SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2236da5199SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2336da5199SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2436da5199SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2536da5199SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2636da5199SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2736da5199SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2836da5199SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2936da5199SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3036da5199SPawel Jakub Dawidek  * SUCH DAMAGE.
3136da5199SPawel Jakub Dawidek  */
3236da5199SPawel Jakub Dawidek 
3336da5199SPawel Jakub Dawidek #include <sys/cdefs.h>
3436da5199SPawel Jakub Dawidek __FBSDID("$FreeBSD$");
3536da5199SPawel Jakub Dawidek 
36586c5854SPawel Jakub Dawidek #include <sys/param.h>
3736da5199SPawel Jakub Dawidek #include <sys/socket.h>
3836da5199SPawel Jakub Dawidek 
3936da5199SPawel Jakub Dawidek #include <errno.h>
4036da5199SPawel Jakub Dawidek #include <fcntl.h>
4136da5199SPawel Jakub Dawidek #include <stdbool.h>
4236da5199SPawel Jakub Dawidek #include <stdint.h>
4336da5199SPawel Jakub Dawidek #include <stdlib.h>
4436da5199SPawel Jakub Dawidek #include <string.h>
4536da5199SPawel Jakub Dawidek #include <unistd.h>
4636da5199SPawel Jakub Dawidek 
4736da5199SPawel Jakub Dawidek #ifdef HAVE_PJDLOG
4836da5199SPawel Jakub Dawidek #include <pjdlog.h>
4936da5199SPawel Jakub Dawidek #endif
5036da5199SPawel Jakub Dawidek 
5136da5199SPawel Jakub Dawidek #include "common_impl.h"
5236da5199SPawel Jakub Dawidek #include "msgio.h"
5336da5199SPawel Jakub Dawidek 
5436da5199SPawel Jakub Dawidek #ifndef	HAVE_PJDLOG
5536da5199SPawel Jakub Dawidek #include <assert.h>
5636da5199SPawel Jakub Dawidek #define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
5736da5199SPawel Jakub Dawidek #define	PJDLOG_RASSERT(expr, ...)	assert(expr)
5836da5199SPawel Jakub Dawidek #define	PJDLOG_ABORT(...)		abort()
5936da5199SPawel Jakub Dawidek #endif
6036da5199SPawel Jakub Dawidek 
61586c5854SPawel Jakub Dawidek #define	PKG_MAX_SIZE	(MCLBYTES / CMSG_SPACE(sizeof(int)) - 1)
62586c5854SPawel Jakub Dawidek 
6336da5199SPawel Jakub Dawidek static int
6436da5199SPawel Jakub Dawidek msghdr_add_fd(struct cmsghdr *cmsg, int fd)
6536da5199SPawel Jakub Dawidek {
6636da5199SPawel Jakub Dawidek 
6736da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(fd >= 0);
6836da5199SPawel Jakub Dawidek 
6936da5199SPawel Jakub Dawidek 	cmsg->cmsg_level = SOL_SOCKET;
7036da5199SPawel Jakub Dawidek 	cmsg->cmsg_type = SCM_RIGHTS;
7136da5199SPawel Jakub Dawidek 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
7236da5199SPawel Jakub Dawidek 	bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
7336da5199SPawel Jakub Dawidek 
7436da5199SPawel Jakub Dawidek 	return (0);
7536da5199SPawel Jakub Dawidek }
7636da5199SPawel Jakub Dawidek 
7736da5199SPawel Jakub Dawidek static int
7836da5199SPawel Jakub Dawidek msghdr_get_fd(struct cmsghdr *cmsg)
7936da5199SPawel Jakub Dawidek {
8036da5199SPawel Jakub Dawidek 	int fd;
8136da5199SPawel Jakub Dawidek 
8236da5199SPawel Jakub Dawidek 	if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET ||
8336da5199SPawel Jakub Dawidek 	    cmsg->cmsg_type != SCM_RIGHTS ||
8436da5199SPawel Jakub Dawidek 	    cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) {
8536da5199SPawel Jakub Dawidek 		errno = EINVAL;
8636da5199SPawel Jakub Dawidek 		return (-1);
8736da5199SPawel Jakub Dawidek 	}
8836da5199SPawel Jakub Dawidek 
8936da5199SPawel Jakub Dawidek 	bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd));
9036da5199SPawel Jakub Dawidek #ifndef MSG_CMSG_CLOEXEC
9136da5199SPawel Jakub Dawidek 	/*
9236da5199SPawel Jakub Dawidek 	 * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the
9336da5199SPawel Jakub Dawidek 	 * close-on-exec flag atomically, but we still want to set it for
9436da5199SPawel Jakub Dawidek 	 * consistency.
9536da5199SPawel Jakub Dawidek 	 */
9636da5199SPawel Jakub Dawidek 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
9736da5199SPawel Jakub Dawidek #endif
9836da5199SPawel Jakub Dawidek 
9936da5199SPawel Jakub Dawidek 	return (fd);
10036da5199SPawel Jakub Dawidek }
10136da5199SPawel Jakub Dawidek 
10236da5199SPawel Jakub Dawidek static void
10336da5199SPawel Jakub Dawidek fd_wait(int fd, bool doread)
10436da5199SPawel Jakub Dawidek {
10536da5199SPawel Jakub Dawidek 	fd_set fds;
10636da5199SPawel Jakub Dawidek 
10736da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(fd >= 0);
10836da5199SPawel Jakub Dawidek 
10936da5199SPawel Jakub Dawidek 	FD_ZERO(&fds);
11036da5199SPawel Jakub Dawidek 	FD_SET(fd, &fds);
11136da5199SPawel Jakub Dawidek 	(void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds,
11236da5199SPawel Jakub Dawidek 	    NULL, NULL);
11336da5199SPawel Jakub Dawidek }
11436da5199SPawel Jakub Dawidek 
11536da5199SPawel Jakub Dawidek static int
11636da5199SPawel Jakub Dawidek msg_recv(int sock, struct msghdr *msg)
11736da5199SPawel Jakub Dawidek {
11836da5199SPawel Jakub Dawidek 	int flags;
11936da5199SPawel Jakub Dawidek 
12036da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
12136da5199SPawel Jakub Dawidek 
12236da5199SPawel Jakub Dawidek #ifdef MSG_CMSG_CLOEXEC
12336da5199SPawel Jakub Dawidek 	flags = MSG_CMSG_CLOEXEC;
12436da5199SPawel Jakub Dawidek #else
12536da5199SPawel Jakub Dawidek 	flags = 0;
12636da5199SPawel Jakub Dawidek #endif
12736da5199SPawel Jakub Dawidek 
12836da5199SPawel Jakub Dawidek 	for (;;) {
12936da5199SPawel Jakub Dawidek 		fd_wait(sock, true);
13036da5199SPawel Jakub Dawidek 		if (recvmsg(sock, msg, flags) == -1) {
13136da5199SPawel Jakub Dawidek 			if (errno == EINTR)
13236da5199SPawel Jakub Dawidek 				continue;
13336da5199SPawel Jakub Dawidek 			return (-1);
13436da5199SPawel Jakub Dawidek 		}
13536da5199SPawel Jakub Dawidek 		break;
13636da5199SPawel Jakub Dawidek 	}
13736da5199SPawel Jakub Dawidek 
13836da5199SPawel Jakub Dawidek 	return (0);
13936da5199SPawel Jakub Dawidek }
14036da5199SPawel Jakub Dawidek 
14136da5199SPawel Jakub Dawidek static int
14236da5199SPawel Jakub Dawidek msg_send(int sock, const struct msghdr *msg)
14336da5199SPawel Jakub Dawidek {
14436da5199SPawel Jakub Dawidek 
14536da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
14636da5199SPawel Jakub Dawidek 
14736da5199SPawel Jakub Dawidek 	for (;;) {
14836da5199SPawel Jakub Dawidek 		fd_wait(sock, false);
14936da5199SPawel Jakub Dawidek 		if (sendmsg(sock, msg, 0) == -1) {
15036da5199SPawel Jakub Dawidek 			if (errno == EINTR)
15136da5199SPawel Jakub Dawidek 				continue;
15236da5199SPawel Jakub Dawidek 			return (-1);
15336da5199SPawel Jakub Dawidek 		}
15436da5199SPawel Jakub Dawidek 		break;
15536da5199SPawel Jakub Dawidek 	}
15636da5199SPawel Jakub Dawidek 
15736da5199SPawel Jakub Dawidek 	return (0);
15836da5199SPawel Jakub Dawidek }
15936da5199SPawel Jakub Dawidek 
160*032f0fbbSAlex Richardson /*
161*032f0fbbSAlex Richardson  * MacOS/Linux do not define struct cmsgcred but we need to bootstrap libnv
162*032f0fbbSAlex Richardson  * when building on non-FreeBSD systems. Since they are not used during
163*032f0fbbSAlex Richardson  * bootstrap we can just omit these two functions there.
164*032f0fbbSAlex Richardson  */
165*032f0fbbSAlex Richardson #ifndef __FreeBSD__
166*032f0fbbSAlex Richardson #warning "cred_send() not supported on non-FreeBSD systems"
167*032f0fbbSAlex Richardson #else
16836da5199SPawel Jakub Dawidek int
16936da5199SPawel Jakub Dawidek cred_send(int sock)
17036da5199SPawel Jakub Dawidek {
17136da5199SPawel Jakub Dawidek 	unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
17236da5199SPawel Jakub Dawidek 	struct msghdr msg;
17336da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
17436da5199SPawel Jakub Dawidek 	struct iovec iov;
17536da5199SPawel Jakub Dawidek 	uint8_t dummy;
17636da5199SPawel Jakub Dawidek 
17736da5199SPawel Jakub Dawidek 	bzero(credbuf, sizeof(credbuf));
17836da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
17936da5199SPawel Jakub Dawidek 	bzero(&iov, sizeof(iov));
18036da5199SPawel Jakub Dawidek 
18136da5199SPawel Jakub Dawidek 	/*
18236da5199SPawel Jakub Dawidek 	 * XXX: We send one byte along with the control message, because
18336da5199SPawel Jakub Dawidek 	 *      setting msg_iov to NULL only works if this is the first
18436da5199SPawel Jakub Dawidek 	 *      packet send over the socket. Once we send some data we
18536da5199SPawel Jakub Dawidek 	 *      won't be able to send credentials anymore. This is most
18636da5199SPawel Jakub Dawidek 	 *      likely a kernel bug.
18736da5199SPawel Jakub Dawidek 	 */
18836da5199SPawel Jakub Dawidek 	dummy = 0;
18936da5199SPawel Jakub Dawidek 	iov.iov_base = &dummy;
19036da5199SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
19136da5199SPawel Jakub Dawidek 
19236da5199SPawel Jakub Dawidek 	msg.msg_iov = &iov;
19336da5199SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
19436da5199SPawel Jakub Dawidek 	msg.msg_control = credbuf;
19536da5199SPawel Jakub Dawidek 	msg.msg_controllen = sizeof(credbuf);
19636da5199SPawel Jakub Dawidek 
19736da5199SPawel Jakub Dawidek 	cmsg = CMSG_FIRSTHDR(&msg);
19836da5199SPawel Jakub Dawidek 	cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
19936da5199SPawel Jakub Dawidek 	cmsg->cmsg_level = SOL_SOCKET;
20036da5199SPawel Jakub Dawidek 	cmsg->cmsg_type = SCM_CREDS;
20136da5199SPawel Jakub Dawidek 
20236da5199SPawel Jakub Dawidek 	if (msg_send(sock, &msg) == -1)
20336da5199SPawel Jakub Dawidek 		return (-1);
20436da5199SPawel Jakub Dawidek 
20536da5199SPawel Jakub Dawidek 	return (0);
20636da5199SPawel Jakub Dawidek }
20736da5199SPawel Jakub Dawidek 
20836da5199SPawel Jakub Dawidek int
20936da5199SPawel Jakub Dawidek cred_recv(int sock, struct cmsgcred *cred)
21036da5199SPawel Jakub Dawidek {
21136da5199SPawel Jakub Dawidek 	unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
21236da5199SPawel Jakub Dawidek 	struct msghdr msg;
21336da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
21436da5199SPawel Jakub Dawidek 	struct iovec iov;
21536da5199SPawel Jakub Dawidek 	uint8_t dummy;
21636da5199SPawel Jakub Dawidek 
21736da5199SPawel Jakub Dawidek 	bzero(credbuf, sizeof(credbuf));
21836da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
21936da5199SPawel Jakub Dawidek 	bzero(&iov, sizeof(iov));
22036da5199SPawel Jakub Dawidek 
22136da5199SPawel Jakub Dawidek 	iov.iov_base = &dummy;
22236da5199SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
22336da5199SPawel Jakub Dawidek 
22436da5199SPawel Jakub Dawidek 	msg.msg_iov = &iov;
22536da5199SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
22636da5199SPawel Jakub Dawidek 	msg.msg_control = credbuf;
22736da5199SPawel Jakub Dawidek 	msg.msg_controllen = sizeof(credbuf);
22836da5199SPawel Jakub Dawidek 
22936da5199SPawel Jakub Dawidek 	if (msg_recv(sock, &msg) == -1)
23036da5199SPawel Jakub Dawidek 		return (-1);
23136da5199SPawel Jakub Dawidek 
23236da5199SPawel Jakub Dawidek 	cmsg = CMSG_FIRSTHDR(&msg);
23336da5199SPawel Jakub Dawidek 	if (cmsg == NULL ||
23436da5199SPawel Jakub Dawidek 	    cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) ||
23536da5199SPawel Jakub Dawidek 	    cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) {
23636da5199SPawel Jakub Dawidek 		errno = EINVAL;
23736da5199SPawel Jakub Dawidek 		return (-1);
23836da5199SPawel Jakub Dawidek 	}
23936da5199SPawel Jakub Dawidek 	bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred));
24036da5199SPawel Jakub Dawidek 
24136da5199SPawel Jakub Dawidek 	return (0);
24236da5199SPawel Jakub Dawidek }
243*032f0fbbSAlex Richardson #endif
24436da5199SPawel Jakub Dawidek 
245586c5854SPawel Jakub Dawidek static int
246586c5854SPawel Jakub Dawidek fd_package_send(int sock, const int *fds, size_t nfds)
24736da5199SPawel Jakub Dawidek {
24836da5199SPawel Jakub Dawidek 	struct msghdr msg;
24936da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
250586c5854SPawel Jakub Dawidek 	struct iovec iov;
25136da5199SPawel Jakub Dawidek 	unsigned int i;
25236da5199SPawel Jakub Dawidek 	int serrno, ret;
253586c5854SPawel Jakub Dawidek 	uint8_t dummy;
25436da5199SPawel Jakub Dawidek 
255586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
256586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(fds != NULL);
257586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(nfds > 0);
25836da5199SPawel Jakub Dawidek 
25936da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
260586c5854SPawel Jakub Dawidek 
261586c5854SPawel Jakub Dawidek 	/*
262586c5854SPawel Jakub Dawidek 	 * XXX: Look into cred_send function for more details.
263586c5854SPawel Jakub Dawidek 	 */
264586c5854SPawel Jakub Dawidek 	dummy = 0;
265586c5854SPawel Jakub Dawidek 	iov.iov_base = &dummy;
266586c5854SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
267586c5854SPawel Jakub Dawidek 
268586c5854SPawel Jakub Dawidek 	msg.msg_iov = &iov;
269586c5854SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
27036da5199SPawel Jakub Dawidek 	msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
27136da5199SPawel Jakub Dawidek 	msg.msg_control = calloc(1, msg.msg_controllen);
27236da5199SPawel Jakub Dawidek 	if (msg.msg_control == NULL)
27336da5199SPawel Jakub Dawidek 		return (-1);
27436da5199SPawel Jakub Dawidek 
27536da5199SPawel Jakub Dawidek 	ret = -1;
27636da5199SPawel Jakub Dawidek 
27736da5199SPawel Jakub Dawidek 	for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
27836da5199SPawel Jakub Dawidek 	    i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
27936da5199SPawel Jakub Dawidek 		if (msghdr_add_fd(cmsg, fds[i]) == -1)
28036da5199SPawel Jakub Dawidek 			goto end;
28136da5199SPawel Jakub Dawidek 	}
28236da5199SPawel Jakub Dawidek 
28336da5199SPawel Jakub Dawidek 	if (msg_send(sock, &msg) == -1)
28436da5199SPawel Jakub Dawidek 		goto end;
28536da5199SPawel Jakub Dawidek 
28636da5199SPawel Jakub Dawidek 	ret = 0;
28736da5199SPawel Jakub Dawidek end:
28836da5199SPawel Jakub Dawidek 	serrno = errno;
28936da5199SPawel Jakub Dawidek 	free(msg.msg_control);
29036da5199SPawel Jakub Dawidek 	errno = serrno;
29136da5199SPawel Jakub Dawidek 	return (ret);
29236da5199SPawel Jakub Dawidek }
29336da5199SPawel Jakub Dawidek 
294586c5854SPawel Jakub Dawidek static int
295586c5854SPawel Jakub Dawidek fd_package_recv(int sock, int *fds, size_t nfds)
29636da5199SPawel Jakub Dawidek {
29736da5199SPawel Jakub Dawidek 	struct msghdr msg;
29836da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
29936da5199SPawel Jakub Dawidek 	unsigned int i;
30036da5199SPawel Jakub Dawidek 	int serrno, ret;
301586c5854SPawel Jakub Dawidek 	struct iovec iov;
302586c5854SPawel Jakub Dawidek 	uint8_t dummy;
30336da5199SPawel Jakub Dawidek 
304586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
305586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(nfds > 0);
306586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(fds != NULL);
30736da5199SPawel Jakub Dawidek 
30836da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
309586c5854SPawel Jakub Dawidek 	bzero(&iov, sizeof(iov));
310586c5854SPawel Jakub Dawidek 
311586c5854SPawel Jakub Dawidek 	/*
312586c5854SPawel Jakub Dawidek 	 * XXX: Look into cred_send function for more details.
313586c5854SPawel Jakub Dawidek 	 */
314586c5854SPawel Jakub Dawidek 	iov.iov_base = &dummy;
315586c5854SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
316586c5854SPawel Jakub Dawidek 
317586c5854SPawel Jakub Dawidek 	msg.msg_iov = &iov;
318586c5854SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
31936da5199SPawel Jakub Dawidek 	msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
32036da5199SPawel Jakub Dawidek 	msg.msg_control = calloc(1, msg.msg_controllen);
32136da5199SPawel Jakub Dawidek 	if (msg.msg_control == NULL)
32236da5199SPawel Jakub Dawidek 		return (-1);
32336da5199SPawel Jakub Dawidek 
32436da5199SPawel Jakub Dawidek 	ret = -1;
32536da5199SPawel Jakub Dawidek 
32636da5199SPawel Jakub Dawidek 	if (msg_recv(sock, &msg) == -1)
32736da5199SPawel Jakub Dawidek 		goto end;
32836da5199SPawel Jakub Dawidek 
32936da5199SPawel Jakub Dawidek 	for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
33036da5199SPawel Jakub Dawidek 	    i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
33136da5199SPawel Jakub Dawidek 		fds[i] = msghdr_get_fd(cmsg);
33236da5199SPawel Jakub Dawidek 		if (fds[i] < 0)
33336da5199SPawel Jakub Dawidek 			break;
33436da5199SPawel Jakub Dawidek 	}
33536da5199SPawel Jakub Dawidek 
33636da5199SPawel Jakub Dawidek 	if (cmsg != NULL || i < nfds) {
33736da5199SPawel Jakub Dawidek 		int fd;
33836da5199SPawel Jakub Dawidek 
33936da5199SPawel Jakub Dawidek 		/*
34036da5199SPawel Jakub Dawidek 		 * We need to close all received descriptors, even if we have
34136da5199SPawel Jakub Dawidek 		 * different control message (eg. SCM_CREDS) in between.
34236da5199SPawel Jakub Dawidek 		 */
34336da5199SPawel Jakub Dawidek 		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
34436da5199SPawel Jakub Dawidek 		    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
34536da5199SPawel Jakub Dawidek 			fd = msghdr_get_fd(cmsg);
34636da5199SPawel Jakub Dawidek 			if (fd >= 0)
34736da5199SPawel Jakub Dawidek 				close(fd);
34836da5199SPawel Jakub Dawidek 		}
34936da5199SPawel Jakub Dawidek 		errno = EINVAL;
35036da5199SPawel Jakub Dawidek 		goto end;
35136da5199SPawel Jakub Dawidek 	}
35236da5199SPawel Jakub Dawidek 
35336da5199SPawel Jakub Dawidek 	ret = 0;
35436da5199SPawel Jakub Dawidek end:
35536da5199SPawel Jakub Dawidek 	serrno = errno;
35636da5199SPawel Jakub Dawidek 	free(msg.msg_control);
35736da5199SPawel Jakub Dawidek 	errno = serrno;
35836da5199SPawel Jakub Dawidek 	return (ret);
35936da5199SPawel Jakub Dawidek }
36036da5199SPawel Jakub Dawidek 
36136da5199SPawel Jakub Dawidek int
362586c5854SPawel Jakub Dawidek fd_recv(int sock, int *fds, size_t nfds)
363586c5854SPawel Jakub Dawidek {
364586c5854SPawel Jakub Dawidek 	unsigned int i, step, j;
365586c5854SPawel Jakub Dawidek 	int ret, serrno;
366586c5854SPawel Jakub Dawidek 
367586c5854SPawel Jakub Dawidek 	if (nfds == 0 || fds == NULL) {
368586c5854SPawel Jakub Dawidek 		errno = EINVAL;
369586c5854SPawel Jakub Dawidek 		return (-1);
370586c5854SPawel Jakub Dawidek 	}
371586c5854SPawel Jakub Dawidek 
372586c5854SPawel Jakub Dawidek 	ret = i = step = 0;
373586c5854SPawel Jakub Dawidek 	while (i < nfds) {
374586c5854SPawel Jakub Dawidek 		if (PKG_MAX_SIZE < nfds - i)
375586c5854SPawel Jakub Dawidek 			step = PKG_MAX_SIZE;
376586c5854SPawel Jakub Dawidek 		else
377586c5854SPawel Jakub Dawidek 			step = nfds - i;
378586c5854SPawel Jakub Dawidek 		ret = fd_package_recv(sock, fds + i, step);
379586c5854SPawel Jakub Dawidek 		if (ret != 0) {
380586c5854SPawel Jakub Dawidek 			/* Close all received descriptors. */
381586c5854SPawel Jakub Dawidek 			serrno = errno;
382586c5854SPawel Jakub Dawidek 			for (j = 0; j < i; j++)
383586c5854SPawel Jakub Dawidek 				close(fds[j]);
384586c5854SPawel Jakub Dawidek 			errno = serrno;
385586c5854SPawel Jakub Dawidek 			break;
386586c5854SPawel Jakub Dawidek 		}
387586c5854SPawel Jakub Dawidek 		i += step;
388586c5854SPawel Jakub Dawidek 	}
389586c5854SPawel Jakub Dawidek 
390586c5854SPawel Jakub Dawidek 	return (ret);
391586c5854SPawel Jakub Dawidek }
392586c5854SPawel Jakub Dawidek 
393586c5854SPawel Jakub Dawidek int
394586c5854SPawel Jakub Dawidek fd_send(int sock, const int *fds, size_t nfds)
395586c5854SPawel Jakub Dawidek {
396586c5854SPawel Jakub Dawidek 	unsigned int i, step;
397586c5854SPawel Jakub Dawidek 	int ret;
398586c5854SPawel Jakub Dawidek 
399586c5854SPawel Jakub Dawidek 	if (nfds == 0 || fds == NULL) {
400586c5854SPawel Jakub Dawidek 		errno = EINVAL;
401586c5854SPawel Jakub Dawidek 		return (-1);
402586c5854SPawel Jakub Dawidek 	}
403586c5854SPawel Jakub Dawidek 
404586c5854SPawel Jakub Dawidek 	ret = i = step = 0;
405586c5854SPawel Jakub Dawidek 	while (i < nfds) {
406586c5854SPawel Jakub Dawidek 		if (PKG_MAX_SIZE < nfds - i)
407586c5854SPawel Jakub Dawidek 			step = PKG_MAX_SIZE;
408586c5854SPawel Jakub Dawidek 		else
409586c5854SPawel Jakub Dawidek 			step = nfds - i;
410586c5854SPawel Jakub Dawidek 		ret = fd_package_send(sock, fds + i, step);
411586c5854SPawel Jakub Dawidek 		if (ret != 0)
412586c5854SPawel Jakub Dawidek 			break;
413586c5854SPawel Jakub Dawidek 		i += step;
414586c5854SPawel Jakub Dawidek 	}
415586c5854SPawel Jakub Dawidek 
416586c5854SPawel Jakub Dawidek 	return (ret);
417586c5854SPawel Jakub Dawidek }
418586c5854SPawel Jakub Dawidek 
419586c5854SPawel Jakub Dawidek int
42036da5199SPawel Jakub Dawidek buf_send(int sock, void *buf, size_t size)
42136da5199SPawel Jakub Dawidek {
42236da5199SPawel Jakub Dawidek 	ssize_t done;
42336da5199SPawel Jakub Dawidek 	unsigned char *ptr;
42436da5199SPawel Jakub Dawidek 
4253d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
4263d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(size > 0);
4273d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(buf != NULL);
4283d34eceaSPawel Jakub Dawidek 
42936da5199SPawel Jakub Dawidek 	ptr = buf;
43036da5199SPawel Jakub Dawidek 	do {
43136da5199SPawel Jakub Dawidek 		fd_wait(sock, false);
43236da5199SPawel Jakub Dawidek 		done = send(sock, ptr, size, 0);
43336da5199SPawel Jakub Dawidek 		if (done == -1) {
43436da5199SPawel Jakub Dawidek 			if (errno == EINTR)
43536da5199SPawel Jakub Dawidek 				continue;
43636da5199SPawel Jakub Dawidek 			return (-1);
43736da5199SPawel Jakub Dawidek 		} else if (done == 0) {
43836da5199SPawel Jakub Dawidek 			errno = ENOTCONN;
43936da5199SPawel Jakub Dawidek 			return (-1);
44036da5199SPawel Jakub Dawidek 		}
44136da5199SPawel Jakub Dawidek 		size -= done;
44236da5199SPawel Jakub Dawidek 		ptr += done;
44336da5199SPawel Jakub Dawidek 	} while (size > 0);
44436da5199SPawel Jakub Dawidek 
44536da5199SPawel Jakub Dawidek 	return (0);
44636da5199SPawel Jakub Dawidek }
44736da5199SPawel Jakub Dawidek 
44836da5199SPawel Jakub Dawidek int
44936da5199SPawel Jakub Dawidek buf_recv(int sock, void *buf, size_t size)
45036da5199SPawel Jakub Dawidek {
45136da5199SPawel Jakub Dawidek 	ssize_t done;
45236da5199SPawel Jakub Dawidek 	unsigned char *ptr;
45336da5199SPawel Jakub Dawidek 
4543d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
4553d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(buf != NULL);
4563d34eceaSPawel Jakub Dawidek 
45736da5199SPawel Jakub Dawidek 	ptr = buf;
4587f7fe890SPawel Jakub Dawidek 	while (size > 0) {
45936da5199SPawel Jakub Dawidek 		fd_wait(sock, true);
46036da5199SPawel Jakub Dawidek 		done = recv(sock, ptr, size, 0);
46136da5199SPawel Jakub Dawidek 		if (done == -1) {
46236da5199SPawel Jakub Dawidek 			if (errno == EINTR)
46336da5199SPawel Jakub Dawidek 				continue;
46436da5199SPawel Jakub Dawidek 			return (-1);
46536da5199SPawel Jakub Dawidek 		} else if (done == 0) {
46636da5199SPawel Jakub Dawidek 			errno = ENOTCONN;
46736da5199SPawel Jakub Dawidek 			return (-1);
46836da5199SPawel Jakub Dawidek 		}
46936da5199SPawel Jakub Dawidek 		size -= done;
47036da5199SPawel Jakub Dawidek 		ptr += done;
4717f7fe890SPawel Jakub Dawidek 	}
47236da5199SPawel Jakub Dawidek 
47336da5199SPawel Jakub Dawidek 	return (0);
47436da5199SPawel Jakub Dawidek }
475