xref: /freebsd/lib/libnv/msgio.c (revision 3810ba1b33c9301b7d62a38fded4c8a04524465e)
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>
38*3810ba1bSMariusz Zaborski #include <sys/select.h>
3936da5199SPawel Jakub Dawidek 
4036da5199SPawel Jakub Dawidek #include <errno.h>
4136da5199SPawel Jakub Dawidek #include <fcntl.h>
4236da5199SPawel Jakub Dawidek #include <stdbool.h>
4336da5199SPawel Jakub Dawidek #include <stdint.h>
4436da5199SPawel Jakub Dawidek #include <stdlib.h>
4536da5199SPawel Jakub Dawidek #include <string.h>
4636da5199SPawel Jakub Dawidek #include <unistd.h>
4736da5199SPawel Jakub Dawidek 
4836da5199SPawel Jakub Dawidek #ifdef HAVE_PJDLOG
4936da5199SPawel Jakub Dawidek #include <pjdlog.h>
5036da5199SPawel Jakub Dawidek #endif
5136da5199SPawel Jakub Dawidek 
5236da5199SPawel Jakub Dawidek #include "common_impl.h"
5336da5199SPawel Jakub Dawidek #include "msgio.h"
5436da5199SPawel Jakub Dawidek 
5536da5199SPawel Jakub Dawidek #ifndef	HAVE_PJDLOG
5636da5199SPawel Jakub Dawidek #include <assert.h>
5736da5199SPawel Jakub Dawidek #define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
5836da5199SPawel Jakub Dawidek #define	PJDLOG_RASSERT(expr, ...)	assert(expr)
5936da5199SPawel Jakub Dawidek #define	PJDLOG_ABORT(...)		abort()
6036da5199SPawel Jakub Dawidek #endif
6136da5199SPawel Jakub Dawidek 
62*3810ba1bSMariusz Zaborski #ifdef __linux__
63*3810ba1bSMariusz Zaborski /* Linux: arbitrary size, but must be lower than SCM_MAX_FD. */
64*3810ba1bSMariusz Zaborski #define	PKG_MAX_SIZE	((64U - 1) * CMSG_SPACE(sizeof(int)))
65*3810ba1bSMariusz Zaborski #else
66586c5854SPawel Jakub Dawidek #define	PKG_MAX_SIZE	(MCLBYTES / CMSG_SPACE(sizeof(int)) - 1)
67*3810ba1bSMariusz Zaborski #endif
68586c5854SPawel Jakub Dawidek 
6936da5199SPawel Jakub Dawidek static int
7036da5199SPawel Jakub Dawidek msghdr_add_fd(struct cmsghdr *cmsg, int fd)
7136da5199SPawel Jakub Dawidek {
7236da5199SPawel Jakub Dawidek 
7336da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(fd >= 0);
7436da5199SPawel Jakub Dawidek 
7536da5199SPawel Jakub Dawidek 	cmsg->cmsg_level = SOL_SOCKET;
7636da5199SPawel Jakub Dawidek 	cmsg->cmsg_type = SCM_RIGHTS;
7736da5199SPawel Jakub Dawidek 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
7836da5199SPawel Jakub Dawidek 	bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
7936da5199SPawel Jakub Dawidek 
8036da5199SPawel Jakub Dawidek 	return (0);
8136da5199SPawel Jakub Dawidek }
8236da5199SPawel Jakub Dawidek 
8336da5199SPawel Jakub Dawidek static void
8436da5199SPawel Jakub Dawidek fd_wait(int fd, bool doread)
8536da5199SPawel Jakub Dawidek {
8636da5199SPawel Jakub Dawidek 	fd_set fds;
8736da5199SPawel Jakub Dawidek 
8836da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(fd >= 0);
8936da5199SPawel Jakub Dawidek 
9036da5199SPawel Jakub Dawidek 	FD_ZERO(&fds);
9136da5199SPawel Jakub Dawidek 	FD_SET(fd, &fds);
9236da5199SPawel Jakub Dawidek 	(void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds,
9336da5199SPawel Jakub Dawidek 	    NULL, NULL);
9436da5199SPawel Jakub Dawidek }
9536da5199SPawel Jakub Dawidek 
9636da5199SPawel Jakub Dawidek static int
9736da5199SPawel Jakub Dawidek msg_recv(int sock, struct msghdr *msg)
9836da5199SPawel Jakub Dawidek {
9936da5199SPawel Jakub Dawidek 	int flags;
10036da5199SPawel Jakub Dawidek 
10136da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
10236da5199SPawel Jakub Dawidek 
10336da5199SPawel Jakub Dawidek #ifdef MSG_CMSG_CLOEXEC
10436da5199SPawel Jakub Dawidek 	flags = MSG_CMSG_CLOEXEC;
10536da5199SPawel Jakub Dawidek #else
10636da5199SPawel Jakub Dawidek 	flags = 0;
10736da5199SPawel Jakub Dawidek #endif
10836da5199SPawel Jakub Dawidek 
10936da5199SPawel Jakub Dawidek 	for (;;) {
11036da5199SPawel Jakub Dawidek 		fd_wait(sock, true);
11136da5199SPawel Jakub Dawidek 		if (recvmsg(sock, msg, flags) == -1) {
11236da5199SPawel Jakub Dawidek 			if (errno == EINTR)
11336da5199SPawel Jakub Dawidek 				continue;
11436da5199SPawel Jakub Dawidek 			return (-1);
11536da5199SPawel Jakub Dawidek 		}
11636da5199SPawel Jakub Dawidek 		break;
11736da5199SPawel Jakub Dawidek 	}
11836da5199SPawel Jakub Dawidek 
11936da5199SPawel Jakub Dawidek 	return (0);
12036da5199SPawel Jakub Dawidek }
12136da5199SPawel Jakub Dawidek 
12236da5199SPawel Jakub Dawidek static int
12336da5199SPawel Jakub Dawidek msg_send(int sock, const struct msghdr *msg)
12436da5199SPawel Jakub Dawidek {
12536da5199SPawel Jakub Dawidek 
12636da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
12736da5199SPawel Jakub Dawidek 
12836da5199SPawel Jakub Dawidek 	for (;;) {
12936da5199SPawel Jakub Dawidek 		fd_wait(sock, false);
13036da5199SPawel Jakub Dawidek 		if (sendmsg(sock, msg, 0) == -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 
141*3810ba1bSMariusz Zaborski #ifdef __FreeBSD__
14236da5199SPawel Jakub Dawidek int
14336da5199SPawel Jakub Dawidek cred_send(int sock)
14436da5199SPawel Jakub Dawidek {
14536da5199SPawel Jakub Dawidek 	unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
14636da5199SPawel Jakub Dawidek 	struct msghdr msg;
14736da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
14836da5199SPawel Jakub Dawidek 	struct iovec iov;
14936da5199SPawel Jakub Dawidek 	uint8_t dummy;
15036da5199SPawel Jakub Dawidek 
15136da5199SPawel Jakub Dawidek 	bzero(credbuf, sizeof(credbuf));
15236da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
15336da5199SPawel Jakub Dawidek 	bzero(&iov, sizeof(iov));
15436da5199SPawel Jakub Dawidek 
15536da5199SPawel Jakub Dawidek 	/*
15636da5199SPawel Jakub Dawidek 	 * XXX: We send one byte along with the control message, because
15736da5199SPawel Jakub Dawidek 	 *      setting msg_iov to NULL only works if this is the first
15836da5199SPawel Jakub Dawidek 	 *      packet send over the socket. Once we send some data we
15936da5199SPawel Jakub Dawidek 	 *      won't be able to send credentials anymore. This is most
16036da5199SPawel Jakub Dawidek 	 *      likely a kernel bug.
16136da5199SPawel Jakub Dawidek 	 */
16236da5199SPawel Jakub Dawidek 	dummy = 0;
16336da5199SPawel Jakub Dawidek 	iov.iov_base = &dummy;
16436da5199SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
16536da5199SPawel Jakub Dawidek 
16636da5199SPawel Jakub Dawidek 	msg.msg_iov = &iov;
16736da5199SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
16836da5199SPawel Jakub Dawidek 	msg.msg_control = credbuf;
16936da5199SPawel Jakub Dawidek 	msg.msg_controllen = sizeof(credbuf);
17036da5199SPawel Jakub Dawidek 
17136da5199SPawel Jakub Dawidek 	cmsg = CMSG_FIRSTHDR(&msg);
17236da5199SPawel Jakub Dawidek 	cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
17336da5199SPawel Jakub Dawidek 	cmsg->cmsg_level = SOL_SOCKET;
17436da5199SPawel Jakub Dawidek 	cmsg->cmsg_type = SCM_CREDS;
17536da5199SPawel Jakub Dawidek 
17636da5199SPawel Jakub Dawidek 	if (msg_send(sock, &msg) == -1)
17736da5199SPawel Jakub Dawidek 		return (-1);
17836da5199SPawel Jakub Dawidek 
17936da5199SPawel Jakub Dawidek 	return (0);
18036da5199SPawel Jakub Dawidek }
18136da5199SPawel Jakub Dawidek 
18236da5199SPawel Jakub Dawidek int
18336da5199SPawel Jakub Dawidek cred_recv(int sock, struct cmsgcred *cred)
18436da5199SPawel Jakub Dawidek {
18536da5199SPawel Jakub Dawidek 	unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
18636da5199SPawel Jakub Dawidek 	struct msghdr msg;
18736da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
18836da5199SPawel Jakub Dawidek 	struct iovec iov;
18936da5199SPawel Jakub Dawidek 	uint8_t dummy;
19036da5199SPawel Jakub Dawidek 
19136da5199SPawel Jakub Dawidek 	bzero(credbuf, sizeof(credbuf));
19236da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
19336da5199SPawel Jakub Dawidek 	bzero(&iov, sizeof(iov));
19436da5199SPawel Jakub Dawidek 
19536da5199SPawel Jakub Dawidek 	iov.iov_base = &dummy;
19636da5199SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
19736da5199SPawel Jakub Dawidek 
19836da5199SPawel Jakub Dawidek 	msg.msg_iov = &iov;
19936da5199SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
20036da5199SPawel Jakub Dawidek 	msg.msg_control = credbuf;
20136da5199SPawel Jakub Dawidek 	msg.msg_controllen = sizeof(credbuf);
20236da5199SPawel Jakub Dawidek 
20336da5199SPawel Jakub Dawidek 	if (msg_recv(sock, &msg) == -1)
20436da5199SPawel Jakub Dawidek 		return (-1);
20536da5199SPawel Jakub Dawidek 
20636da5199SPawel Jakub Dawidek 	cmsg = CMSG_FIRSTHDR(&msg);
20736da5199SPawel Jakub Dawidek 	if (cmsg == NULL ||
20836da5199SPawel Jakub Dawidek 	    cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) ||
20936da5199SPawel Jakub Dawidek 	    cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) {
21036da5199SPawel Jakub Dawidek 		errno = EINVAL;
21136da5199SPawel Jakub Dawidek 		return (-1);
21236da5199SPawel Jakub Dawidek 	}
21336da5199SPawel Jakub Dawidek 	bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred));
21436da5199SPawel Jakub Dawidek 
21536da5199SPawel Jakub Dawidek 	return (0);
21636da5199SPawel Jakub Dawidek }
217032f0fbbSAlex Richardson #endif
21836da5199SPawel Jakub Dawidek 
219586c5854SPawel Jakub Dawidek static int
220586c5854SPawel Jakub Dawidek fd_package_send(int sock, const int *fds, size_t nfds)
22136da5199SPawel Jakub Dawidek {
22236da5199SPawel Jakub Dawidek 	struct msghdr msg;
22336da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
224586c5854SPawel Jakub Dawidek 	struct iovec iov;
22536da5199SPawel Jakub Dawidek 	unsigned int i;
22636da5199SPawel Jakub Dawidek 	int serrno, ret;
227586c5854SPawel Jakub Dawidek 	uint8_t dummy;
22836da5199SPawel Jakub Dawidek 
229586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
230586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(fds != NULL);
231586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(nfds > 0);
23236da5199SPawel Jakub Dawidek 
23336da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
234586c5854SPawel Jakub Dawidek 
235586c5854SPawel Jakub Dawidek 	/*
236586c5854SPawel Jakub Dawidek 	 * XXX: Look into cred_send function for more details.
237586c5854SPawel Jakub Dawidek 	 */
238586c5854SPawel Jakub Dawidek 	dummy = 0;
239586c5854SPawel Jakub Dawidek 	iov.iov_base = &dummy;
240586c5854SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
241586c5854SPawel Jakub Dawidek 
242586c5854SPawel Jakub Dawidek 	msg.msg_iov = &iov;
243586c5854SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
24436da5199SPawel Jakub Dawidek 	msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
24536da5199SPawel Jakub Dawidek 	msg.msg_control = calloc(1, msg.msg_controllen);
24636da5199SPawel Jakub Dawidek 	if (msg.msg_control == NULL)
24736da5199SPawel Jakub Dawidek 		return (-1);
24836da5199SPawel Jakub Dawidek 
24936da5199SPawel Jakub Dawidek 	ret = -1;
25036da5199SPawel Jakub Dawidek 
25136da5199SPawel Jakub Dawidek 	for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
25236da5199SPawel Jakub Dawidek 	    i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
25336da5199SPawel Jakub Dawidek 		if (msghdr_add_fd(cmsg, fds[i]) == -1)
25436da5199SPawel Jakub Dawidek 			goto end;
25536da5199SPawel Jakub Dawidek 	}
25636da5199SPawel Jakub Dawidek 
25736da5199SPawel Jakub Dawidek 	if (msg_send(sock, &msg) == -1)
25836da5199SPawel Jakub Dawidek 		goto end;
25936da5199SPawel Jakub Dawidek 
26036da5199SPawel Jakub Dawidek 	ret = 0;
26136da5199SPawel Jakub Dawidek end:
26236da5199SPawel Jakub Dawidek 	serrno = errno;
26336da5199SPawel Jakub Dawidek 	free(msg.msg_control);
26436da5199SPawel Jakub Dawidek 	errno = serrno;
26536da5199SPawel Jakub Dawidek 	return (ret);
26636da5199SPawel Jakub Dawidek }
26736da5199SPawel Jakub Dawidek 
268586c5854SPawel Jakub Dawidek static int
269586c5854SPawel Jakub Dawidek fd_package_recv(int sock, int *fds, size_t nfds)
27036da5199SPawel Jakub Dawidek {
27136da5199SPawel Jakub Dawidek 	struct msghdr msg;
27236da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
27336da5199SPawel Jakub Dawidek 	unsigned int i;
27436da5199SPawel Jakub Dawidek 	int serrno, ret;
275586c5854SPawel Jakub Dawidek 	struct iovec iov;
276586c5854SPawel Jakub Dawidek 	uint8_t dummy;
27736da5199SPawel Jakub Dawidek 
278586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
279586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(nfds > 0);
280586c5854SPawel Jakub Dawidek 	PJDLOG_ASSERT(fds != NULL);
28136da5199SPawel Jakub Dawidek 
28236da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
283586c5854SPawel Jakub Dawidek 	bzero(&iov, sizeof(iov));
284586c5854SPawel Jakub Dawidek 
285586c5854SPawel Jakub Dawidek 	/*
286586c5854SPawel Jakub Dawidek 	 * XXX: Look into cred_send function for more details.
287586c5854SPawel Jakub Dawidek 	 */
288586c5854SPawel Jakub Dawidek 	iov.iov_base = &dummy;
289586c5854SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
290586c5854SPawel Jakub Dawidek 
291586c5854SPawel Jakub Dawidek 	msg.msg_iov = &iov;
292586c5854SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
29336da5199SPawel Jakub Dawidek 	msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
29436da5199SPawel Jakub Dawidek 	msg.msg_control = calloc(1, msg.msg_controllen);
29536da5199SPawel Jakub Dawidek 	if (msg.msg_control == NULL)
29636da5199SPawel Jakub Dawidek 		return (-1);
29736da5199SPawel Jakub Dawidek 
29836da5199SPawel Jakub Dawidek 	ret = -1;
29936da5199SPawel Jakub Dawidek 
30036da5199SPawel Jakub Dawidek 	if (msg_recv(sock, &msg) == -1)
30136da5199SPawel Jakub Dawidek 		goto end;
30236da5199SPawel Jakub Dawidek 
303*3810ba1bSMariusz Zaborski 	i = 0;
304*3810ba1bSMariusz Zaborski 	cmsg = CMSG_FIRSTHDR(&msg);
305*3810ba1bSMariusz Zaborski 	while (cmsg && i < nfds) {
306*3810ba1bSMariusz Zaborski 		unsigned int n;
307*3810ba1bSMariusz Zaborski 
308*3810ba1bSMariusz Zaborski 		if (cmsg->cmsg_level != SOL_SOCKET ||
309*3810ba1bSMariusz Zaborski 		    cmsg->cmsg_type != SCM_RIGHTS) {
310*3810ba1bSMariusz Zaborski 			errno = EINVAL;
31136da5199SPawel Jakub Dawidek 			break;
31236da5199SPawel Jakub Dawidek 		}
313*3810ba1bSMariusz Zaborski 		n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
314*3810ba1bSMariusz Zaborski 		if (i + n > nfds) {
315*3810ba1bSMariusz Zaborski 			errno = EINVAL;
316*3810ba1bSMariusz Zaborski 			break;
317*3810ba1bSMariusz Zaborski 		}
318*3810ba1bSMariusz Zaborski 		bcopy(CMSG_DATA(cmsg), fds + i, sizeof(int) * n);
319*3810ba1bSMariusz Zaborski 		cmsg = CMSG_NXTHDR(&msg, cmsg);
320*3810ba1bSMariusz Zaborski 		i += n;
321*3810ba1bSMariusz Zaborski 	}
32236da5199SPawel Jakub Dawidek 
32336da5199SPawel Jakub Dawidek 	if (cmsg != NULL || i < nfds) {
324*3810ba1bSMariusz Zaborski 		unsigned int last;
32536da5199SPawel Jakub Dawidek 
32636da5199SPawel Jakub Dawidek 		/*
32736da5199SPawel Jakub Dawidek 		 * We need to close all received descriptors, even if we have
32836da5199SPawel Jakub Dawidek 		 * different control message (eg. SCM_CREDS) in between.
32936da5199SPawel Jakub Dawidek 		 */
330*3810ba1bSMariusz Zaborski 		last = i;
331*3810ba1bSMariusz Zaborski 		for (i = 0; i < last; i++) {
332*3810ba1bSMariusz Zaborski 			if (fds[i] >= 0) {
333*3810ba1bSMariusz Zaborski 				close(fds[i]);
334*3810ba1bSMariusz Zaborski 			}
33536da5199SPawel Jakub Dawidek 		}
33636da5199SPawel Jakub Dawidek 		errno = EINVAL;
33736da5199SPawel Jakub Dawidek 		goto end;
33836da5199SPawel Jakub Dawidek 	}
33936da5199SPawel Jakub Dawidek 
340*3810ba1bSMariusz Zaborski #ifndef MSG_CMSG_CLOEXEC
341*3810ba1bSMariusz Zaborski 	/*
342*3810ba1bSMariusz Zaborski 	 * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the
343*3810ba1bSMariusz Zaborski 	 * close-on-exec flag atomically, but we still want to set it for
344*3810ba1bSMariusz Zaborski 	 * consistency.
345*3810ba1bSMariusz Zaborski 	 */
346*3810ba1bSMariusz Zaborski 	for (i = 0; i < nfds; i++) {
347*3810ba1bSMariusz Zaborski 		(void) fcntl(fds[i], F_SETFD, FD_CLOEXEC);
348*3810ba1bSMariusz Zaborski 	}
349*3810ba1bSMariusz Zaborski #endif
350*3810ba1bSMariusz Zaborski 
35136da5199SPawel Jakub Dawidek 	ret = 0;
35236da5199SPawel Jakub Dawidek end:
35336da5199SPawel Jakub Dawidek 	serrno = errno;
35436da5199SPawel Jakub Dawidek 	free(msg.msg_control);
35536da5199SPawel Jakub Dawidek 	errno = serrno;
35636da5199SPawel Jakub Dawidek 	return (ret);
35736da5199SPawel Jakub Dawidek }
35836da5199SPawel Jakub Dawidek 
35936da5199SPawel Jakub Dawidek int
360586c5854SPawel Jakub Dawidek fd_recv(int sock, int *fds, size_t nfds)
361586c5854SPawel Jakub Dawidek {
362586c5854SPawel Jakub Dawidek 	unsigned int i, step, j;
363586c5854SPawel Jakub Dawidek 	int ret, serrno;
364586c5854SPawel Jakub Dawidek 
365586c5854SPawel Jakub Dawidek 	if (nfds == 0 || fds == NULL) {
366586c5854SPawel Jakub Dawidek 		errno = EINVAL;
367586c5854SPawel Jakub Dawidek 		return (-1);
368586c5854SPawel Jakub Dawidek 	}
369586c5854SPawel Jakub Dawidek 
370586c5854SPawel Jakub Dawidek 	ret = i = step = 0;
371586c5854SPawel Jakub Dawidek 	while (i < nfds) {
372586c5854SPawel Jakub Dawidek 		if (PKG_MAX_SIZE < nfds - i)
373586c5854SPawel Jakub Dawidek 			step = PKG_MAX_SIZE;
374586c5854SPawel Jakub Dawidek 		else
375586c5854SPawel Jakub Dawidek 			step = nfds - i;
376586c5854SPawel Jakub Dawidek 		ret = fd_package_recv(sock, fds + i, step);
377586c5854SPawel Jakub Dawidek 		if (ret != 0) {
378586c5854SPawel Jakub Dawidek 			/* Close all received descriptors. */
379586c5854SPawel Jakub Dawidek 			serrno = errno;
380586c5854SPawel Jakub Dawidek 			for (j = 0; j < i; j++)
381586c5854SPawel Jakub Dawidek 				close(fds[j]);
382586c5854SPawel Jakub Dawidek 			errno = serrno;
383586c5854SPawel Jakub Dawidek 			break;
384586c5854SPawel Jakub Dawidek 		}
385586c5854SPawel Jakub Dawidek 		i += step;
386586c5854SPawel Jakub Dawidek 	}
387586c5854SPawel Jakub Dawidek 
388586c5854SPawel Jakub Dawidek 	return (ret);
389586c5854SPawel Jakub Dawidek }
390586c5854SPawel Jakub Dawidek 
391586c5854SPawel Jakub Dawidek int
392586c5854SPawel Jakub Dawidek fd_send(int sock, const int *fds, size_t nfds)
393586c5854SPawel Jakub Dawidek {
394586c5854SPawel Jakub Dawidek 	unsigned int i, step;
395586c5854SPawel Jakub Dawidek 	int ret;
396586c5854SPawel Jakub Dawidek 
397586c5854SPawel Jakub Dawidek 	if (nfds == 0 || fds == NULL) {
398586c5854SPawel Jakub Dawidek 		errno = EINVAL;
399586c5854SPawel Jakub Dawidek 		return (-1);
400586c5854SPawel Jakub Dawidek 	}
401586c5854SPawel Jakub Dawidek 
402586c5854SPawel Jakub Dawidek 	ret = i = step = 0;
403586c5854SPawel Jakub Dawidek 	while (i < nfds) {
404586c5854SPawel Jakub Dawidek 		if (PKG_MAX_SIZE < nfds - i)
405586c5854SPawel Jakub Dawidek 			step = PKG_MAX_SIZE;
406586c5854SPawel Jakub Dawidek 		else
407586c5854SPawel Jakub Dawidek 			step = nfds - i;
408586c5854SPawel Jakub Dawidek 		ret = fd_package_send(sock, fds + i, step);
409586c5854SPawel Jakub Dawidek 		if (ret != 0)
410586c5854SPawel Jakub Dawidek 			break;
411586c5854SPawel Jakub Dawidek 		i += step;
412586c5854SPawel Jakub Dawidek 	}
413586c5854SPawel Jakub Dawidek 
414586c5854SPawel Jakub Dawidek 	return (ret);
415586c5854SPawel Jakub Dawidek }
416586c5854SPawel Jakub Dawidek 
417586c5854SPawel Jakub Dawidek int
41836da5199SPawel Jakub Dawidek buf_send(int sock, void *buf, size_t size)
41936da5199SPawel Jakub Dawidek {
42036da5199SPawel Jakub Dawidek 	ssize_t done;
42136da5199SPawel Jakub Dawidek 	unsigned char *ptr;
42236da5199SPawel Jakub Dawidek 
4233d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
4243d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(size > 0);
4253d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(buf != NULL);
4263d34eceaSPawel Jakub Dawidek 
42736da5199SPawel Jakub Dawidek 	ptr = buf;
42836da5199SPawel Jakub Dawidek 	do {
42936da5199SPawel Jakub Dawidek 		fd_wait(sock, false);
43036da5199SPawel Jakub Dawidek 		done = send(sock, ptr, size, 0);
43136da5199SPawel Jakub Dawidek 		if (done == -1) {
43236da5199SPawel Jakub Dawidek 			if (errno == EINTR)
43336da5199SPawel Jakub Dawidek 				continue;
43436da5199SPawel Jakub Dawidek 			return (-1);
43536da5199SPawel Jakub Dawidek 		} else if (done == 0) {
43636da5199SPawel Jakub Dawidek 			errno = ENOTCONN;
43736da5199SPawel Jakub Dawidek 			return (-1);
43836da5199SPawel Jakub Dawidek 		}
43936da5199SPawel Jakub Dawidek 		size -= done;
44036da5199SPawel Jakub Dawidek 		ptr += done;
44136da5199SPawel Jakub Dawidek 	} while (size > 0);
44236da5199SPawel Jakub Dawidek 
44336da5199SPawel Jakub Dawidek 	return (0);
44436da5199SPawel Jakub Dawidek }
44536da5199SPawel Jakub Dawidek 
44636da5199SPawel Jakub Dawidek int
44736da5199SPawel Jakub Dawidek buf_recv(int sock, void *buf, size_t size)
44836da5199SPawel Jakub Dawidek {
44936da5199SPawel Jakub Dawidek 	ssize_t done;
45036da5199SPawel Jakub Dawidek 	unsigned char *ptr;
45136da5199SPawel Jakub Dawidek 
4523d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
4533d34eceaSPawel Jakub Dawidek 	PJDLOG_ASSERT(buf != NULL);
4543d34eceaSPawel Jakub Dawidek 
45536da5199SPawel Jakub Dawidek 	ptr = buf;
4567f7fe890SPawel Jakub Dawidek 	while (size > 0) {
45736da5199SPawel Jakub Dawidek 		fd_wait(sock, true);
45836da5199SPawel Jakub Dawidek 		done = recv(sock, ptr, size, 0);
45936da5199SPawel Jakub Dawidek 		if (done == -1) {
46036da5199SPawel Jakub Dawidek 			if (errno == EINTR)
46136da5199SPawel Jakub Dawidek 				continue;
46236da5199SPawel Jakub Dawidek 			return (-1);
46336da5199SPawel Jakub Dawidek 		} else if (done == 0) {
46436da5199SPawel Jakub Dawidek 			errno = ENOTCONN;
46536da5199SPawel Jakub Dawidek 			return (-1);
46636da5199SPawel Jakub Dawidek 		}
46736da5199SPawel Jakub Dawidek 		size -= done;
46836da5199SPawel Jakub Dawidek 		ptr += done;
4697f7fe890SPawel Jakub Dawidek 	}
47036da5199SPawel Jakub Dawidek 
47136da5199SPawel Jakub Dawidek 	return (0);
47236da5199SPawel Jakub Dawidek }
473