xref: /freebsd/lib/libnv/msgio.c (revision 7f7fe890a5a687075c40a764584e5a0e29a4d833)
136da5199SPawel Jakub Dawidek /*-
236da5199SPawel Jakub Dawidek  * Copyright (c) 2013 The FreeBSD Foundation
336da5199SPawel Jakub Dawidek  * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
436da5199SPawel Jakub Dawidek  * All rights reserved.
536da5199SPawel Jakub Dawidek  *
636da5199SPawel Jakub Dawidek  * This software was developed by Pawel Jakub Dawidek under sponsorship from
736da5199SPawel Jakub Dawidek  * the FreeBSD Foundation.
836da5199SPawel Jakub Dawidek  *
936da5199SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
1036da5199SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
1136da5199SPawel Jakub Dawidek  * are met:
1236da5199SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
1336da5199SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1436da5199SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1536da5199SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1636da5199SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1736da5199SPawel Jakub Dawidek  *
1836da5199SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1936da5199SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2036da5199SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2136da5199SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2236da5199SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2336da5199SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2436da5199SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2536da5199SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2636da5199SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2736da5199SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2836da5199SPawel Jakub Dawidek  * SUCH DAMAGE.
2936da5199SPawel Jakub Dawidek  */
3036da5199SPawel Jakub Dawidek 
3136da5199SPawel Jakub Dawidek #include <sys/cdefs.h>
3236da5199SPawel Jakub Dawidek __FBSDID("$FreeBSD$");
3336da5199SPawel Jakub Dawidek 
3436da5199SPawel Jakub Dawidek #include <sys/types.h>
3536da5199SPawel Jakub Dawidek #include <sys/socket.h>
3636da5199SPawel Jakub Dawidek 
3736da5199SPawel Jakub Dawidek #include <errno.h>
3836da5199SPawel Jakub Dawidek #include <fcntl.h>
3936da5199SPawel Jakub Dawidek #include <stdbool.h>
4036da5199SPawel Jakub Dawidek #include <stdint.h>
4136da5199SPawel Jakub Dawidek #include <stdlib.h>
4236da5199SPawel Jakub Dawidek #include <string.h>
4336da5199SPawel Jakub Dawidek #include <unistd.h>
4436da5199SPawel Jakub Dawidek 
4536da5199SPawel Jakub Dawidek #ifdef HAVE_PJDLOG
4636da5199SPawel Jakub Dawidek #include <pjdlog.h>
4736da5199SPawel Jakub Dawidek #endif
4836da5199SPawel Jakub Dawidek 
4936da5199SPawel Jakub Dawidek #include "common_impl.h"
5036da5199SPawel Jakub Dawidek #include "msgio.h"
5136da5199SPawel Jakub Dawidek 
5236da5199SPawel Jakub Dawidek #ifndef	HAVE_PJDLOG
5336da5199SPawel Jakub Dawidek #include <assert.h>
5436da5199SPawel Jakub Dawidek #define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
5536da5199SPawel Jakub Dawidek #define	PJDLOG_RASSERT(expr, ...)	assert(expr)
5636da5199SPawel Jakub Dawidek #define	PJDLOG_ABORT(...)		abort()
5736da5199SPawel Jakub Dawidek #endif
5836da5199SPawel Jakub Dawidek 
5936da5199SPawel Jakub Dawidek static int
6036da5199SPawel Jakub Dawidek msghdr_add_fd(struct cmsghdr *cmsg, int fd)
6136da5199SPawel Jakub Dawidek {
6236da5199SPawel Jakub Dawidek 
6336da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(fd >= 0);
6436da5199SPawel Jakub Dawidek 
6536da5199SPawel Jakub Dawidek 	if (!fd_is_valid(fd)) {
6636da5199SPawel Jakub Dawidek 		errno = EBADF;
6736da5199SPawel Jakub Dawidek 		return (-1);
6836da5199SPawel Jakub Dawidek 	}
6936da5199SPawel Jakub Dawidek 
7036da5199SPawel Jakub Dawidek 	cmsg->cmsg_level = SOL_SOCKET;
7136da5199SPawel Jakub Dawidek 	cmsg->cmsg_type = SCM_RIGHTS;
7236da5199SPawel Jakub Dawidek 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
7336da5199SPawel Jakub Dawidek 	bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
7436da5199SPawel Jakub Dawidek 
7536da5199SPawel Jakub Dawidek 	return (0);
7636da5199SPawel Jakub Dawidek }
7736da5199SPawel Jakub Dawidek 
7836da5199SPawel Jakub Dawidek static int
7936da5199SPawel Jakub Dawidek msghdr_get_fd(struct cmsghdr *cmsg)
8036da5199SPawel Jakub Dawidek {
8136da5199SPawel Jakub Dawidek 	int fd;
8236da5199SPawel Jakub Dawidek 
8336da5199SPawel Jakub Dawidek 	if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET ||
8436da5199SPawel Jakub Dawidek 	    cmsg->cmsg_type != SCM_RIGHTS ||
8536da5199SPawel Jakub Dawidek 	    cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) {
8636da5199SPawel Jakub Dawidek 		errno = EINVAL;
8736da5199SPawel Jakub Dawidek 		return (-1);
8836da5199SPawel Jakub Dawidek 	}
8936da5199SPawel Jakub Dawidek 
9036da5199SPawel Jakub Dawidek 	bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd));
9136da5199SPawel Jakub Dawidek #ifndef MSG_CMSG_CLOEXEC
9236da5199SPawel Jakub Dawidek 	/*
9336da5199SPawel Jakub Dawidek 	 * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the
9436da5199SPawel Jakub Dawidek 	 * close-on-exec flag atomically, but we still want to set it for
9536da5199SPawel Jakub Dawidek 	 * consistency.
9636da5199SPawel Jakub Dawidek 	 */
9736da5199SPawel Jakub Dawidek 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
9836da5199SPawel Jakub Dawidek #endif
9936da5199SPawel Jakub Dawidek 
10036da5199SPawel Jakub Dawidek 	return (fd);
10136da5199SPawel Jakub Dawidek }
10236da5199SPawel Jakub Dawidek 
10336da5199SPawel Jakub Dawidek static void
10436da5199SPawel Jakub Dawidek fd_wait(int fd, bool doread)
10536da5199SPawel Jakub Dawidek {
10636da5199SPawel Jakub Dawidek 	fd_set fds;
10736da5199SPawel Jakub Dawidek 
10836da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(fd >= 0);
10936da5199SPawel Jakub Dawidek 
11036da5199SPawel Jakub Dawidek 	FD_ZERO(&fds);
11136da5199SPawel Jakub Dawidek 	FD_SET(fd, &fds);
11236da5199SPawel Jakub Dawidek 	(void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds,
11336da5199SPawel Jakub Dawidek 	    NULL, NULL);
11436da5199SPawel Jakub Dawidek }
11536da5199SPawel Jakub Dawidek 
11636da5199SPawel Jakub Dawidek static int
11736da5199SPawel Jakub Dawidek msg_recv(int sock, struct msghdr *msg)
11836da5199SPawel Jakub Dawidek {
11936da5199SPawel Jakub Dawidek 	int flags;
12036da5199SPawel Jakub Dawidek 
12136da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
12236da5199SPawel Jakub Dawidek 
12336da5199SPawel Jakub Dawidek #ifdef MSG_CMSG_CLOEXEC
12436da5199SPawel Jakub Dawidek 	flags = MSG_CMSG_CLOEXEC;
12536da5199SPawel Jakub Dawidek #else
12636da5199SPawel Jakub Dawidek 	flags = 0;
12736da5199SPawel Jakub Dawidek #endif
12836da5199SPawel Jakub Dawidek 
12936da5199SPawel Jakub Dawidek 	for (;;) {
13036da5199SPawel Jakub Dawidek 		fd_wait(sock, true);
13136da5199SPawel Jakub Dawidek 		if (recvmsg(sock, msg, flags) == -1) {
13236da5199SPawel Jakub Dawidek 			if (errno == EINTR)
13336da5199SPawel Jakub Dawidek 				continue;
13436da5199SPawel Jakub Dawidek 			return (-1);
13536da5199SPawel Jakub Dawidek 		}
13636da5199SPawel Jakub Dawidek 		break;
13736da5199SPawel Jakub Dawidek 	}
13836da5199SPawel Jakub Dawidek 
13936da5199SPawel Jakub Dawidek 	return (0);
14036da5199SPawel Jakub Dawidek }
14136da5199SPawel Jakub Dawidek 
14236da5199SPawel Jakub Dawidek static int
14336da5199SPawel Jakub Dawidek msg_send(int sock, const struct msghdr *msg)
14436da5199SPawel Jakub Dawidek {
14536da5199SPawel Jakub Dawidek 
14636da5199SPawel Jakub Dawidek 	PJDLOG_ASSERT(sock >= 0);
14736da5199SPawel Jakub Dawidek 
14836da5199SPawel Jakub Dawidek 	for (;;) {
14936da5199SPawel Jakub Dawidek 		fd_wait(sock, false);
15036da5199SPawel Jakub Dawidek 		if (sendmsg(sock, msg, 0) == -1) {
15136da5199SPawel Jakub Dawidek 			if (errno == EINTR)
15236da5199SPawel Jakub Dawidek 				continue;
15336da5199SPawel Jakub Dawidek 			return (-1);
15436da5199SPawel Jakub Dawidek 		}
15536da5199SPawel Jakub Dawidek 		break;
15636da5199SPawel Jakub Dawidek 	}
15736da5199SPawel Jakub Dawidek 
15836da5199SPawel Jakub Dawidek 	return (0);
15936da5199SPawel Jakub Dawidek }
16036da5199SPawel Jakub Dawidek 
16136da5199SPawel Jakub Dawidek int
16236da5199SPawel Jakub Dawidek cred_send(int sock)
16336da5199SPawel Jakub Dawidek {
16436da5199SPawel Jakub Dawidek 	unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
16536da5199SPawel Jakub Dawidek 	struct msghdr msg;
16636da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
16736da5199SPawel Jakub Dawidek 	struct iovec iov;
16836da5199SPawel Jakub Dawidek 	uint8_t dummy;
16936da5199SPawel Jakub Dawidek 
17036da5199SPawel Jakub Dawidek 	bzero(credbuf, sizeof(credbuf));
17136da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
17236da5199SPawel Jakub Dawidek 	bzero(&iov, sizeof(iov));
17336da5199SPawel Jakub Dawidek 
17436da5199SPawel Jakub Dawidek 	/*
17536da5199SPawel Jakub Dawidek 	 * XXX: We send one byte along with the control message, because
17636da5199SPawel Jakub Dawidek 	 *      setting msg_iov to NULL only works if this is the first
17736da5199SPawel Jakub Dawidek 	 *      packet send over the socket. Once we send some data we
17836da5199SPawel Jakub Dawidek 	 *      won't be able to send credentials anymore. This is most
17936da5199SPawel Jakub Dawidek 	 *      likely a kernel bug.
18036da5199SPawel Jakub Dawidek 	 */
18136da5199SPawel Jakub Dawidek 	dummy = 0;
18236da5199SPawel Jakub Dawidek 	iov.iov_base = &dummy;
18336da5199SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
18436da5199SPawel Jakub Dawidek 
18536da5199SPawel Jakub Dawidek 	msg.msg_iov = &iov;
18636da5199SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
18736da5199SPawel Jakub Dawidek 	msg.msg_control = credbuf;
18836da5199SPawel Jakub Dawidek 	msg.msg_controllen = sizeof(credbuf);
18936da5199SPawel Jakub Dawidek 
19036da5199SPawel Jakub Dawidek 	cmsg = CMSG_FIRSTHDR(&msg);
19136da5199SPawel Jakub Dawidek 	cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
19236da5199SPawel Jakub Dawidek 	cmsg->cmsg_level = SOL_SOCKET;
19336da5199SPawel Jakub Dawidek 	cmsg->cmsg_type = SCM_CREDS;
19436da5199SPawel Jakub Dawidek 
19536da5199SPawel Jakub Dawidek 	if (msg_send(sock, &msg) == -1)
19636da5199SPawel Jakub Dawidek 		return (-1);
19736da5199SPawel Jakub Dawidek 
19836da5199SPawel Jakub Dawidek 	return (0);
19936da5199SPawel Jakub Dawidek }
20036da5199SPawel Jakub Dawidek 
20136da5199SPawel Jakub Dawidek int
20236da5199SPawel Jakub Dawidek cred_recv(int sock, struct cmsgcred *cred)
20336da5199SPawel Jakub Dawidek {
20436da5199SPawel Jakub Dawidek 	unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
20536da5199SPawel Jakub Dawidek 	struct msghdr msg;
20636da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
20736da5199SPawel Jakub Dawidek 	struct iovec iov;
20836da5199SPawel Jakub Dawidek 	uint8_t dummy;
20936da5199SPawel Jakub Dawidek 
21036da5199SPawel Jakub Dawidek 	bzero(credbuf, sizeof(credbuf));
21136da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
21236da5199SPawel Jakub Dawidek 	bzero(&iov, sizeof(iov));
21336da5199SPawel Jakub Dawidek 
21436da5199SPawel Jakub Dawidek 	iov.iov_base = &dummy;
21536da5199SPawel Jakub Dawidek 	iov.iov_len = sizeof(dummy);
21636da5199SPawel Jakub Dawidek 
21736da5199SPawel Jakub Dawidek 	msg.msg_iov = &iov;
21836da5199SPawel Jakub Dawidek 	msg.msg_iovlen = 1;
21936da5199SPawel Jakub Dawidek 	msg.msg_control = credbuf;
22036da5199SPawel Jakub Dawidek 	msg.msg_controllen = sizeof(credbuf);
22136da5199SPawel Jakub Dawidek 
22236da5199SPawel Jakub Dawidek 	if (msg_recv(sock, &msg) == -1)
22336da5199SPawel Jakub Dawidek 		return (-1);
22436da5199SPawel Jakub Dawidek 
22536da5199SPawel Jakub Dawidek 	cmsg = CMSG_FIRSTHDR(&msg);
22636da5199SPawel Jakub Dawidek 	if (cmsg == NULL ||
22736da5199SPawel Jakub Dawidek 	    cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) ||
22836da5199SPawel Jakub Dawidek 	    cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) {
22936da5199SPawel Jakub Dawidek 		errno = EINVAL;
23036da5199SPawel Jakub Dawidek 		return (-1);
23136da5199SPawel Jakub Dawidek 	}
23236da5199SPawel Jakub Dawidek 	bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred));
23336da5199SPawel Jakub Dawidek 
23436da5199SPawel Jakub Dawidek 	return (0);
23536da5199SPawel Jakub Dawidek }
23636da5199SPawel Jakub Dawidek 
23736da5199SPawel Jakub Dawidek int
23836da5199SPawel Jakub Dawidek fd_send(int sock, const int *fds, size_t nfds)
23936da5199SPawel Jakub Dawidek {
24036da5199SPawel Jakub Dawidek 	struct msghdr msg;
24136da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
24236da5199SPawel Jakub Dawidek 	unsigned int i;
24336da5199SPawel Jakub Dawidek 	int serrno, ret;
24436da5199SPawel Jakub Dawidek 
24536da5199SPawel Jakub Dawidek 	if (nfds == 0 || fds == NULL) {
24636da5199SPawel Jakub Dawidek 		errno = EINVAL;
24736da5199SPawel Jakub Dawidek 		return (-1);
24836da5199SPawel Jakub Dawidek 	}
24936da5199SPawel Jakub Dawidek 
25036da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
25136da5199SPawel Jakub Dawidek 	msg.msg_iov = NULL;
25236da5199SPawel Jakub Dawidek 	msg.msg_iovlen = 0;
25336da5199SPawel Jakub Dawidek 	msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
25436da5199SPawel Jakub Dawidek 	msg.msg_control = calloc(1, msg.msg_controllen);
25536da5199SPawel Jakub Dawidek 	if (msg.msg_control == NULL)
25636da5199SPawel Jakub Dawidek 		return (-1);
25736da5199SPawel Jakub Dawidek 
25836da5199SPawel Jakub Dawidek 	ret = -1;
25936da5199SPawel Jakub Dawidek 
26036da5199SPawel Jakub Dawidek 	for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
26136da5199SPawel Jakub Dawidek 	    i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
26236da5199SPawel Jakub Dawidek 		if (msghdr_add_fd(cmsg, fds[i]) == -1)
26336da5199SPawel Jakub Dawidek 			goto end;
26436da5199SPawel Jakub Dawidek 	}
26536da5199SPawel Jakub Dawidek 
26636da5199SPawel Jakub Dawidek 	if (msg_send(sock, &msg) == -1)
26736da5199SPawel Jakub Dawidek 		goto end;
26836da5199SPawel Jakub Dawidek 
26936da5199SPawel Jakub Dawidek 	ret = 0;
27036da5199SPawel Jakub Dawidek end:
27136da5199SPawel Jakub Dawidek 	serrno = errno;
27236da5199SPawel Jakub Dawidek 	free(msg.msg_control);
27336da5199SPawel Jakub Dawidek 	errno = serrno;
27436da5199SPawel Jakub Dawidek 	return (ret);
27536da5199SPawel Jakub Dawidek }
27636da5199SPawel Jakub Dawidek 
27736da5199SPawel Jakub Dawidek int
27836da5199SPawel Jakub Dawidek fd_recv(int sock, int *fds, size_t nfds)
27936da5199SPawel Jakub Dawidek {
28036da5199SPawel Jakub Dawidek 	struct msghdr msg;
28136da5199SPawel Jakub Dawidek 	struct cmsghdr *cmsg;
28236da5199SPawel Jakub Dawidek 	unsigned int i;
28336da5199SPawel Jakub Dawidek 	int serrno, ret;
28436da5199SPawel Jakub Dawidek 
28536da5199SPawel Jakub Dawidek 	if (nfds == 0 || fds == NULL) {
28636da5199SPawel Jakub Dawidek 		errno = EINVAL;
28736da5199SPawel Jakub Dawidek 		return (-1);
28836da5199SPawel Jakub Dawidek 	}
28936da5199SPawel Jakub Dawidek 
29036da5199SPawel Jakub Dawidek 	bzero(&msg, sizeof(msg));
29136da5199SPawel Jakub Dawidek 	msg.msg_iov = NULL;
29236da5199SPawel Jakub Dawidek 	msg.msg_iovlen = 0;
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 
30336da5199SPawel Jakub Dawidek 	for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
30436da5199SPawel Jakub Dawidek 	    i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
30536da5199SPawel Jakub Dawidek 		fds[i] = msghdr_get_fd(cmsg);
30636da5199SPawel Jakub Dawidek 		if (fds[i] < 0)
30736da5199SPawel Jakub Dawidek 			break;
30836da5199SPawel Jakub Dawidek 	}
30936da5199SPawel Jakub Dawidek 
31036da5199SPawel Jakub Dawidek 	if (cmsg != NULL || i < nfds) {
31136da5199SPawel Jakub Dawidek 		int fd;
31236da5199SPawel Jakub Dawidek 
31336da5199SPawel Jakub Dawidek 		/*
31436da5199SPawel Jakub Dawidek 		 * We need to close all received descriptors, even if we have
31536da5199SPawel Jakub Dawidek 		 * different control message (eg. SCM_CREDS) in between.
31636da5199SPawel Jakub Dawidek 		 */
31736da5199SPawel Jakub Dawidek 		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
31836da5199SPawel Jakub Dawidek 		    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
31936da5199SPawel Jakub Dawidek 			fd = msghdr_get_fd(cmsg);
32036da5199SPawel Jakub Dawidek 			if (fd >= 0)
32136da5199SPawel Jakub Dawidek 				close(fd);
32236da5199SPawel Jakub Dawidek 		}
32336da5199SPawel Jakub Dawidek 		errno = EINVAL;
32436da5199SPawel Jakub Dawidek 		goto end;
32536da5199SPawel Jakub Dawidek 	}
32636da5199SPawel Jakub Dawidek 
32736da5199SPawel Jakub Dawidek 	ret = 0;
32836da5199SPawel Jakub Dawidek end:
32936da5199SPawel Jakub Dawidek 	serrno = errno;
33036da5199SPawel Jakub Dawidek 	free(msg.msg_control);
33136da5199SPawel Jakub Dawidek 	errno = serrno;
33236da5199SPawel Jakub Dawidek 	return (ret);
33336da5199SPawel Jakub Dawidek }
33436da5199SPawel Jakub Dawidek 
33536da5199SPawel Jakub Dawidek int
33636da5199SPawel Jakub Dawidek buf_send(int sock, void *buf, size_t size)
33736da5199SPawel Jakub Dawidek {
33836da5199SPawel Jakub Dawidek 	ssize_t done;
33936da5199SPawel Jakub Dawidek 	unsigned char *ptr;
34036da5199SPawel Jakub Dawidek 
34136da5199SPawel Jakub Dawidek 	ptr = buf;
34236da5199SPawel Jakub Dawidek 	do {
34336da5199SPawel Jakub Dawidek 		fd_wait(sock, false);
34436da5199SPawel Jakub Dawidek 		done = send(sock, ptr, size, 0);
34536da5199SPawel Jakub Dawidek 		if (done == -1) {
34636da5199SPawel Jakub Dawidek 			if (errno == EINTR)
34736da5199SPawel Jakub Dawidek 				continue;
34836da5199SPawel Jakub Dawidek 			return (-1);
34936da5199SPawel Jakub Dawidek 		} else if (done == 0) {
35036da5199SPawel Jakub Dawidek 			errno = ENOTCONN;
35136da5199SPawel Jakub Dawidek 			return (-1);
35236da5199SPawel Jakub Dawidek 		}
35336da5199SPawel Jakub Dawidek 		size -= done;
35436da5199SPawel Jakub Dawidek 		ptr += done;
35536da5199SPawel Jakub Dawidek 	} while (size > 0);
35636da5199SPawel Jakub Dawidek 
35736da5199SPawel Jakub Dawidek 	return (0);
35836da5199SPawel Jakub Dawidek }
35936da5199SPawel Jakub Dawidek 
36036da5199SPawel Jakub Dawidek int
36136da5199SPawel Jakub Dawidek buf_recv(int sock, void *buf, size_t size)
36236da5199SPawel Jakub Dawidek {
36336da5199SPawel Jakub Dawidek 	ssize_t done;
36436da5199SPawel Jakub Dawidek 	unsigned char *ptr;
36536da5199SPawel Jakub Dawidek 
36636da5199SPawel Jakub Dawidek 	ptr = buf;
367*7f7fe890SPawel Jakub Dawidek 	while (size > 0) {
36836da5199SPawel Jakub Dawidek 		fd_wait(sock, true);
36936da5199SPawel Jakub Dawidek 		done = recv(sock, ptr, size, 0);
37036da5199SPawel Jakub Dawidek 		if (done == -1) {
37136da5199SPawel Jakub Dawidek 			if (errno == EINTR)
37236da5199SPawel Jakub Dawidek 				continue;
37336da5199SPawel Jakub Dawidek 			return (-1);
37436da5199SPawel Jakub Dawidek 		} else if (done == 0) {
37536da5199SPawel Jakub Dawidek 			errno = ENOTCONN;
37636da5199SPawel Jakub Dawidek 			return (-1);
37736da5199SPawel Jakub Dawidek 		}
37836da5199SPawel Jakub Dawidek 		size -= done;
37936da5199SPawel Jakub Dawidek 		ptr += done;
380*7f7fe890SPawel Jakub Dawidek 	}
38136da5199SPawel Jakub Dawidek 
38236da5199SPawel Jakub Dawidek 	return (0);
38336da5199SPawel Jakub Dawidek }
384