136da5199SPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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
33586c5854SPawel Jakub Dawidek #include <sys/param.h>
3436da5199SPawel Jakub Dawidek #include <sys/socket.h>
353810ba1bSMariusz Zaborski #include <sys/select.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
593810ba1bSMariusz Zaborski #ifdef __linux__
603810ba1bSMariusz Zaborski /* Linux: arbitrary size, but must be lower than SCM_MAX_FD. */
613810ba1bSMariusz Zaborski #define PKG_MAX_SIZE ((64U - 1) * CMSG_SPACE(sizeof(int)))
623810ba1bSMariusz Zaborski #else
6307cf2bb6SMark Johnston /*
6407cf2bb6SMark Johnston * To work around limitations in 32-bit emulation on 64-bit kernels, use a
6507cf2bb6SMark Johnston * machine-independent limit on the number of FDs per message. Each control
6607cf2bb6SMark Johnston * message contains 1 FD and requires 12 bytes for the header, 4 pad bytes,
6707cf2bb6SMark Johnston * 4 bytes for the descriptor, and another 4 pad bytes.
6807cf2bb6SMark Johnston */
6907cf2bb6SMark Johnston #define PKG_MAX_SIZE (MCLBYTES / 24)
703810ba1bSMariusz Zaborski #endif
71586c5854SPawel Jakub Dawidek
7236da5199SPawel Jakub Dawidek static int
msghdr_add_fd(struct cmsghdr * cmsg,int fd)7336da5199SPawel Jakub Dawidek msghdr_add_fd(struct cmsghdr *cmsg, int fd)
7436da5199SPawel Jakub Dawidek {
7536da5199SPawel Jakub Dawidek
7636da5199SPawel Jakub Dawidek PJDLOG_ASSERT(fd >= 0);
7736da5199SPawel Jakub Dawidek
7836da5199SPawel Jakub Dawidek cmsg->cmsg_level = SOL_SOCKET;
7936da5199SPawel Jakub Dawidek cmsg->cmsg_type = SCM_RIGHTS;
8036da5199SPawel Jakub Dawidek cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
8136da5199SPawel Jakub Dawidek bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
8236da5199SPawel Jakub Dawidek
8336da5199SPawel Jakub Dawidek return (0);
8436da5199SPawel Jakub Dawidek }
8536da5199SPawel Jakub Dawidek
8636da5199SPawel Jakub Dawidek static void
fd_wait(int fd,bool doread)8736da5199SPawel Jakub Dawidek fd_wait(int fd, bool doread)
8836da5199SPawel Jakub Dawidek {
8936da5199SPawel Jakub Dawidek fd_set fds;
9036da5199SPawel Jakub Dawidek
9136da5199SPawel Jakub Dawidek PJDLOG_ASSERT(fd >= 0);
9236da5199SPawel Jakub Dawidek
9336da5199SPawel Jakub Dawidek FD_ZERO(&fds);
9436da5199SPawel Jakub Dawidek FD_SET(fd, &fds);
9536da5199SPawel Jakub Dawidek (void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds,
9636da5199SPawel Jakub Dawidek NULL, NULL);
9736da5199SPawel Jakub Dawidek }
9836da5199SPawel Jakub Dawidek
9936da5199SPawel Jakub Dawidek static int
msg_recv(int sock,struct msghdr * msg)10036da5199SPawel Jakub Dawidek msg_recv(int sock, struct msghdr *msg)
10136da5199SPawel Jakub Dawidek {
10236da5199SPawel Jakub Dawidek int flags;
10336da5199SPawel Jakub Dawidek
10436da5199SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0);
10536da5199SPawel Jakub Dawidek
10636da5199SPawel Jakub Dawidek #ifdef MSG_CMSG_CLOEXEC
10736da5199SPawel Jakub Dawidek flags = MSG_CMSG_CLOEXEC;
10836da5199SPawel Jakub Dawidek #else
10936da5199SPawel Jakub Dawidek flags = 0;
11036da5199SPawel Jakub Dawidek #endif
11136da5199SPawel Jakub Dawidek
11236da5199SPawel Jakub Dawidek for (;;) {
11336da5199SPawel Jakub Dawidek fd_wait(sock, true);
11436da5199SPawel Jakub Dawidek if (recvmsg(sock, msg, flags) == -1) {
11536da5199SPawel Jakub Dawidek if (errno == EINTR)
11636da5199SPawel Jakub Dawidek continue;
11736da5199SPawel Jakub Dawidek return (-1);
11836da5199SPawel Jakub Dawidek }
11936da5199SPawel Jakub Dawidek break;
12036da5199SPawel Jakub Dawidek }
12136da5199SPawel Jakub Dawidek
12236da5199SPawel Jakub Dawidek return (0);
12336da5199SPawel Jakub Dawidek }
12436da5199SPawel Jakub Dawidek
12536da5199SPawel Jakub Dawidek static int
msg_send(int sock,const struct msghdr * msg)12636da5199SPawel Jakub Dawidek msg_send(int sock, const struct msghdr *msg)
12736da5199SPawel Jakub Dawidek {
12836da5199SPawel Jakub Dawidek
12936da5199SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0);
13036da5199SPawel Jakub Dawidek
13136da5199SPawel Jakub Dawidek for (;;) {
13236da5199SPawel Jakub Dawidek fd_wait(sock, false);
13336da5199SPawel Jakub Dawidek if (sendmsg(sock, msg, 0) == -1) {
13436da5199SPawel Jakub Dawidek if (errno == EINTR)
13536da5199SPawel Jakub Dawidek continue;
13636da5199SPawel Jakub Dawidek return (-1);
13736da5199SPawel Jakub Dawidek }
13836da5199SPawel Jakub Dawidek break;
13936da5199SPawel Jakub Dawidek }
14036da5199SPawel Jakub Dawidek
14136da5199SPawel Jakub Dawidek return (0);
14236da5199SPawel Jakub Dawidek }
14336da5199SPawel Jakub Dawidek
1443810ba1bSMariusz Zaborski #ifdef __FreeBSD__
14536da5199SPawel Jakub Dawidek int
cred_send(int sock)14636da5199SPawel Jakub Dawidek cred_send(int sock)
14736da5199SPawel Jakub Dawidek {
14836da5199SPawel Jakub Dawidek unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
14936da5199SPawel Jakub Dawidek struct msghdr msg;
15036da5199SPawel Jakub Dawidek struct cmsghdr *cmsg;
15136da5199SPawel Jakub Dawidek struct iovec iov;
15236da5199SPawel Jakub Dawidek uint8_t dummy;
15336da5199SPawel Jakub Dawidek
15436da5199SPawel Jakub Dawidek bzero(credbuf, sizeof(credbuf));
15536da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg));
15636da5199SPawel Jakub Dawidek bzero(&iov, sizeof(iov));
15736da5199SPawel Jakub Dawidek
15836da5199SPawel Jakub Dawidek /*
15936da5199SPawel Jakub Dawidek * XXX: We send one byte along with the control message, because
16036da5199SPawel Jakub Dawidek * setting msg_iov to NULL only works if this is the first
16136da5199SPawel Jakub Dawidek * packet send over the socket. Once we send some data we
16236da5199SPawel Jakub Dawidek * won't be able to send credentials anymore. This is most
16336da5199SPawel Jakub Dawidek * likely a kernel bug.
16436da5199SPawel Jakub Dawidek */
16536da5199SPawel Jakub Dawidek dummy = 0;
16636da5199SPawel Jakub Dawidek iov.iov_base = &dummy;
16736da5199SPawel Jakub Dawidek iov.iov_len = sizeof(dummy);
16836da5199SPawel Jakub Dawidek
16936da5199SPawel Jakub Dawidek msg.msg_iov = &iov;
17036da5199SPawel Jakub Dawidek msg.msg_iovlen = 1;
17136da5199SPawel Jakub Dawidek msg.msg_control = credbuf;
17236da5199SPawel Jakub Dawidek msg.msg_controllen = sizeof(credbuf);
17336da5199SPawel Jakub Dawidek
17436da5199SPawel Jakub Dawidek cmsg = CMSG_FIRSTHDR(&msg);
17536da5199SPawel Jakub Dawidek cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
17636da5199SPawel Jakub Dawidek cmsg->cmsg_level = SOL_SOCKET;
17736da5199SPawel Jakub Dawidek cmsg->cmsg_type = SCM_CREDS;
17836da5199SPawel Jakub Dawidek
17936da5199SPawel Jakub Dawidek if (msg_send(sock, &msg) == -1)
18036da5199SPawel Jakub Dawidek return (-1);
18136da5199SPawel Jakub Dawidek
18236da5199SPawel Jakub Dawidek return (0);
18336da5199SPawel Jakub Dawidek }
18436da5199SPawel Jakub Dawidek
18536da5199SPawel Jakub Dawidek int
cred_recv(int sock,struct cmsgcred * cred)18636da5199SPawel Jakub Dawidek cred_recv(int sock, struct cmsgcred *cred)
18736da5199SPawel Jakub Dawidek {
18836da5199SPawel Jakub Dawidek unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
18936da5199SPawel Jakub Dawidek struct msghdr msg;
19036da5199SPawel Jakub Dawidek struct cmsghdr *cmsg;
19136da5199SPawel Jakub Dawidek struct iovec iov;
19236da5199SPawel Jakub Dawidek uint8_t dummy;
19336da5199SPawel Jakub Dawidek
19436da5199SPawel Jakub Dawidek bzero(credbuf, sizeof(credbuf));
19536da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg));
19636da5199SPawel Jakub Dawidek bzero(&iov, sizeof(iov));
19736da5199SPawel Jakub Dawidek
19836da5199SPawel Jakub Dawidek iov.iov_base = &dummy;
19936da5199SPawel Jakub Dawidek iov.iov_len = sizeof(dummy);
20036da5199SPawel Jakub Dawidek
20136da5199SPawel Jakub Dawidek msg.msg_iov = &iov;
20236da5199SPawel Jakub Dawidek msg.msg_iovlen = 1;
20336da5199SPawel Jakub Dawidek msg.msg_control = credbuf;
20436da5199SPawel Jakub Dawidek msg.msg_controllen = sizeof(credbuf);
20536da5199SPawel Jakub Dawidek
20636da5199SPawel Jakub Dawidek if (msg_recv(sock, &msg) == -1)
20736da5199SPawel Jakub Dawidek return (-1);
20836da5199SPawel Jakub Dawidek
20936da5199SPawel Jakub Dawidek cmsg = CMSG_FIRSTHDR(&msg);
21036da5199SPawel Jakub Dawidek if (cmsg == NULL ||
21136da5199SPawel Jakub Dawidek cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) ||
21236da5199SPawel Jakub Dawidek cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) {
21336da5199SPawel Jakub Dawidek errno = EINVAL;
21436da5199SPawel Jakub Dawidek return (-1);
21536da5199SPawel Jakub Dawidek }
21636da5199SPawel Jakub Dawidek bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred));
21736da5199SPawel Jakub Dawidek
21836da5199SPawel Jakub Dawidek return (0);
21936da5199SPawel Jakub Dawidek }
220032f0fbbSAlex Richardson #endif
22136da5199SPawel Jakub Dawidek
222586c5854SPawel Jakub Dawidek static int
fd_package_send(int sock,const int * fds,size_t nfds)223586c5854SPawel Jakub Dawidek fd_package_send(int sock, const int *fds, size_t nfds)
22436da5199SPawel Jakub Dawidek {
22536da5199SPawel Jakub Dawidek struct msghdr msg;
22636da5199SPawel Jakub Dawidek struct cmsghdr *cmsg;
227586c5854SPawel Jakub Dawidek struct iovec iov;
22836da5199SPawel Jakub Dawidek unsigned int i;
22936da5199SPawel Jakub Dawidek int serrno, ret;
230586c5854SPawel Jakub Dawidek uint8_t dummy;
23136da5199SPawel Jakub Dawidek
232586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0);
233586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(fds != NULL);
234586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(nfds > 0);
23536da5199SPawel Jakub Dawidek
23636da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg));
237586c5854SPawel Jakub Dawidek
238586c5854SPawel Jakub Dawidek /*
239586c5854SPawel Jakub Dawidek * XXX: Look into cred_send function for more details.
240586c5854SPawel Jakub Dawidek */
241586c5854SPawel Jakub Dawidek dummy = 0;
242586c5854SPawel Jakub Dawidek iov.iov_base = &dummy;
243586c5854SPawel Jakub Dawidek iov.iov_len = sizeof(dummy);
244586c5854SPawel Jakub Dawidek
245586c5854SPawel Jakub Dawidek msg.msg_iov = &iov;
246586c5854SPawel Jakub Dawidek msg.msg_iovlen = 1;
24736da5199SPawel Jakub Dawidek msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
24836da5199SPawel Jakub Dawidek msg.msg_control = calloc(1, msg.msg_controllen);
24936da5199SPawel Jakub Dawidek if (msg.msg_control == NULL)
25036da5199SPawel Jakub Dawidek return (-1);
25136da5199SPawel Jakub Dawidek
25236da5199SPawel Jakub Dawidek ret = -1;
25336da5199SPawel Jakub Dawidek
25436da5199SPawel Jakub Dawidek for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
25536da5199SPawel Jakub Dawidek i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
25636da5199SPawel Jakub Dawidek if (msghdr_add_fd(cmsg, fds[i]) == -1)
25736da5199SPawel Jakub Dawidek goto end;
25836da5199SPawel Jakub Dawidek }
25936da5199SPawel Jakub Dawidek
26036da5199SPawel Jakub Dawidek if (msg_send(sock, &msg) == -1)
26136da5199SPawel Jakub Dawidek goto end;
26236da5199SPawel Jakub Dawidek
26336da5199SPawel Jakub Dawidek ret = 0;
26436da5199SPawel Jakub Dawidek end:
26536da5199SPawel Jakub Dawidek serrno = errno;
26636da5199SPawel Jakub Dawidek free(msg.msg_control);
26736da5199SPawel Jakub Dawidek errno = serrno;
26836da5199SPawel Jakub Dawidek return (ret);
26936da5199SPawel Jakub Dawidek }
27036da5199SPawel Jakub Dawidek
271586c5854SPawel Jakub Dawidek static int
fd_package_recv(int sock,int * fds,size_t nfds)272586c5854SPawel Jakub Dawidek fd_package_recv(int sock, int *fds, size_t nfds)
27336da5199SPawel Jakub Dawidek {
27436da5199SPawel Jakub Dawidek struct msghdr msg;
27536da5199SPawel Jakub Dawidek struct cmsghdr *cmsg;
27636da5199SPawel Jakub Dawidek unsigned int i;
27736da5199SPawel Jakub Dawidek int serrno, ret;
278586c5854SPawel Jakub Dawidek struct iovec iov;
279586c5854SPawel Jakub Dawidek uint8_t dummy;
28036da5199SPawel Jakub Dawidek
281586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0);
282586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(nfds > 0);
283586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(fds != NULL);
28436da5199SPawel Jakub Dawidek
28536da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg));
286586c5854SPawel Jakub Dawidek bzero(&iov, sizeof(iov));
287586c5854SPawel Jakub Dawidek
288586c5854SPawel Jakub Dawidek /*
289586c5854SPawel Jakub Dawidek * XXX: Look into cred_send function for more details.
290586c5854SPawel Jakub Dawidek */
291586c5854SPawel Jakub Dawidek iov.iov_base = &dummy;
292586c5854SPawel Jakub Dawidek iov.iov_len = sizeof(dummy);
293586c5854SPawel Jakub Dawidek
294586c5854SPawel Jakub Dawidek msg.msg_iov = &iov;
295586c5854SPawel Jakub Dawidek msg.msg_iovlen = 1;
29636da5199SPawel Jakub Dawidek msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
29736da5199SPawel Jakub Dawidek msg.msg_control = calloc(1, msg.msg_controllen);
29836da5199SPawel Jakub Dawidek if (msg.msg_control == NULL)
29936da5199SPawel Jakub Dawidek return (-1);
30036da5199SPawel Jakub Dawidek
30136da5199SPawel Jakub Dawidek ret = -1;
30236da5199SPawel Jakub Dawidek
30336da5199SPawel Jakub Dawidek if (msg_recv(sock, &msg) == -1)
30436da5199SPawel Jakub Dawidek goto end;
30536da5199SPawel Jakub Dawidek
3063810ba1bSMariusz Zaborski i = 0;
3073810ba1bSMariusz Zaborski cmsg = CMSG_FIRSTHDR(&msg);
3083810ba1bSMariusz Zaborski while (cmsg && i < nfds) {
3093810ba1bSMariusz Zaborski unsigned int n;
3103810ba1bSMariusz Zaborski
3113810ba1bSMariusz Zaborski if (cmsg->cmsg_level != SOL_SOCKET ||
3123810ba1bSMariusz Zaborski cmsg->cmsg_type != SCM_RIGHTS) {
3133810ba1bSMariusz Zaborski errno = EINVAL;
31436da5199SPawel Jakub Dawidek break;
31536da5199SPawel Jakub Dawidek }
3163810ba1bSMariusz Zaborski n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
3173810ba1bSMariusz Zaborski if (i + n > nfds) {
3183810ba1bSMariusz Zaborski errno = EINVAL;
3193810ba1bSMariusz Zaborski break;
3203810ba1bSMariusz Zaborski }
3213810ba1bSMariusz Zaborski bcopy(CMSG_DATA(cmsg), fds + i, sizeof(int) * n);
3223810ba1bSMariusz Zaborski cmsg = CMSG_NXTHDR(&msg, cmsg);
3233810ba1bSMariusz Zaborski i += n;
3243810ba1bSMariusz Zaborski }
32536da5199SPawel Jakub Dawidek
32636da5199SPawel Jakub Dawidek if (cmsg != NULL || i < nfds) {
3273810ba1bSMariusz Zaborski unsigned int last;
32836da5199SPawel Jakub Dawidek
32936da5199SPawel Jakub Dawidek /*
33036da5199SPawel Jakub Dawidek * We need to close all received descriptors, even if we have
33136da5199SPawel Jakub Dawidek * different control message (eg. SCM_CREDS) in between.
33236da5199SPawel Jakub Dawidek */
3333810ba1bSMariusz Zaborski last = i;
3343810ba1bSMariusz Zaborski for (i = 0; i < last; i++) {
3353810ba1bSMariusz Zaborski if (fds[i] >= 0) {
3363810ba1bSMariusz Zaborski close(fds[i]);
3373810ba1bSMariusz Zaborski }
33836da5199SPawel Jakub Dawidek }
33936da5199SPawel Jakub Dawidek errno = EINVAL;
34036da5199SPawel Jakub Dawidek goto end;
34136da5199SPawel Jakub Dawidek }
34236da5199SPawel Jakub Dawidek
3433810ba1bSMariusz Zaborski #ifndef MSG_CMSG_CLOEXEC
3443810ba1bSMariusz Zaborski /*
3453810ba1bSMariusz Zaborski * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the
3463810ba1bSMariusz Zaborski * close-on-exec flag atomically, but we still want to set it for
3473810ba1bSMariusz Zaborski * consistency.
3483810ba1bSMariusz Zaborski */
3493810ba1bSMariusz Zaborski for (i = 0; i < nfds; i++) {
3503810ba1bSMariusz Zaborski (void) fcntl(fds[i], F_SETFD, FD_CLOEXEC);
3513810ba1bSMariusz Zaborski }
3523810ba1bSMariusz Zaborski #endif
3533810ba1bSMariusz Zaborski
35436da5199SPawel Jakub Dawidek ret = 0;
35536da5199SPawel Jakub Dawidek end:
35636da5199SPawel Jakub Dawidek serrno = errno;
35736da5199SPawel Jakub Dawidek free(msg.msg_control);
35836da5199SPawel Jakub Dawidek errno = serrno;
35936da5199SPawel Jakub Dawidek return (ret);
36036da5199SPawel Jakub Dawidek }
36136da5199SPawel Jakub Dawidek
36236da5199SPawel Jakub Dawidek int
fd_recv(int sock,int * fds,size_t nfds)363586c5854SPawel Jakub Dawidek fd_recv(int sock, int *fds, size_t nfds)
364586c5854SPawel Jakub Dawidek {
365586c5854SPawel Jakub Dawidek unsigned int i, step, j;
366586c5854SPawel Jakub Dawidek int ret, serrno;
367586c5854SPawel Jakub Dawidek
368586c5854SPawel Jakub Dawidek if (nfds == 0 || fds == NULL) {
369586c5854SPawel Jakub Dawidek errno = EINVAL;
370586c5854SPawel Jakub Dawidek return (-1);
371586c5854SPawel Jakub Dawidek }
372586c5854SPawel Jakub Dawidek
373586c5854SPawel Jakub Dawidek ret = i = step = 0;
374586c5854SPawel Jakub Dawidek while (i < nfds) {
375586c5854SPawel Jakub Dawidek if (PKG_MAX_SIZE < nfds - i)
376586c5854SPawel Jakub Dawidek step = PKG_MAX_SIZE;
377586c5854SPawel Jakub Dawidek else
378586c5854SPawel Jakub Dawidek step = nfds - i;
379586c5854SPawel Jakub Dawidek ret = fd_package_recv(sock, fds + i, step);
380586c5854SPawel Jakub Dawidek if (ret != 0) {
381586c5854SPawel Jakub Dawidek /* Close all received descriptors. */
382586c5854SPawel Jakub Dawidek serrno = errno;
383586c5854SPawel Jakub Dawidek for (j = 0; j < i; j++)
384586c5854SPawel Jakub Dawidek close(fds[j]);
385586c5854SPawel Jakub Dawidek errno = serrno;
386586c5854SPawel Jakub Dawidek break;
387586c5854SPawel Jakub Dawidek }
388586c5854SPawel Jakub Dawidek i += step;
389586c5854SPawel Jakub Dawidek }
390586c5854SPawel Jakub Dawidek
391586c5854SPawel Jakub Dawidek return (ret);
392586c5854SPawel Jakub Dawidek }
393586c5854SPawel Jakub Dawidek
394586c5854SPawel Jakub Dawidek int
fd_send(int sock,const int * fds,size_t nfds)395586c5854SPawel Jakub Dawidek fd_send(int sock, const int *fds, size_t nfds)
396586c5854SPawel Jakub Dawidek {
397586c5854SPawel Jakub Dawidek unsigned int i, step;
398586c5854SPawel Jakub Dawidek int ret;
399586c5854SPawel Jakub Dawidek
400586c5854SPawel Jakub Dawidek if (nfds == 0 || fds == NULL) {
401586c5854SPawel Jakub Dawidek errno = EINVAL;
402586c5854SPawel Jakub Dawidek return (-1);
403586c5854SPawel Jakub Dawidek }
404586c5854SPawel Jakub Dawidek
405586c5854SPawel Jakub Dawidek ret = i = step = 0;
406586c5854SPawel Jakub Dawidek while (i < nfds) {
407586c5854SPawel Jakub Dawidek if (PKG_MAX_SIZE < nfds - i)
408586c5854SPawel Jakub Dawidek step = PKG_MAX_SIZE;
409586c5854SPawel Jakub Dawidek else
410586c5854SPawel Jakub Dawidek step = nfds - i;
411586c5854SPawel Jakub Dawidek ret = fd_package_send(sock, fds + i, step);
412586c5854SPawel Jakub Dawidek if (ret != 0)
413586c5854SPawel Jakub Dawidek break;
414586c5854SPawel Jakub Dawidek i += step;
415586c5854SPawel Jakub Dawidek }
416586c5854SPawel Jakub Dawidek
417586c5854SPawel Jakub Dawidek return (ret);
418586c5854SPawel Jakub Dawidek }
419586c5854SPawel Jakub Dawidek
420586c5854SPawel Jakub Dawidek int
buf_send(int sock,void * buf,size_t size)42136da5199SPawel Jakub Dawidek buf_send(int sock, void *buf, size_t size)
42236da5199SPawel Jakub Dawidek {
42336da5199SPawel Jakub Dawidek ssize_t done;
42436da5199SPawel Jakub Dawidek unsigned char *ptr;
42536da5199SPawel Jakub Dawidek
4263d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0);
4273d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(size > 0);
4283d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(buf != NULL);
4293d34eceaSPawel Jakub Dawidek
43036da5199SPawel Jakub Dawidek ptr = buf;
43136da5199SPawel Jakub Dawidek do {
43236da5199SPawel Jakub Dawidek fd_wait(sock, false);
43336da5199SPawel Jakub Dawidek done = send(sock, ptr, size, 0);
43436da5199SPawel Jakub Dawidek if (done == -1) {
43536da5199SPawel Jakub Dawidek if (errno == EINTR)
43636da5199SPawel Jakub Dawidek continue;
43736da5199SPawel Jakub Dawidek return (-1);
43836da5199SPawel Jakub Dawidek } else if (done == 0) {
43936da5199SPawel Jakub Dawidek errno = ENOTCONN;
44036da5199SPawel Jakub Dawidek return (-1);
44136da5199SPawel Jakub Dawidek }
44236da5199SPawel Jakub Dawidek size -= done;
44336da5199SPawel Jakub Dawidek ptr += done;
44436da5199SPawel Jakub Dawidek } while (size > 0);
44536da5199SPawel Jakub Dawidek
44636da5199SPawel Jakub Dawidek return (0);
44736da5199SPawel Jakub Dawidek }
44836da5199SPawel Jakub Dawidek
44936da5199SPawel Jakub Dawidek int
buf_recv(int sock,void * buf,size_t size,int flags)450db158b99SRobert Wing buf_recv(int sock, void *buf, size_t size, int flags)
45136da5199SPawel Jakub Dawidek {
45236da5199SPawel Jakub Dawidek ssize_t done;
45336da5199SPawel Jakub Dawidek unsigned char *ptr;
45436da5199SPawel Jakub Dawidek
4553d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0);
4563d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(buf != NULL);
4573d34eceaSPawel Jakub Dawidek
45836da5199SPawel Jakub Dawidek ptr = buf;
4597f7fe890SPawel Jakub Dawidek while (size > 0) {
46036da5199SPawel Jakub Dawidek fd_wait(sock, true);
461db158b99SRobert Wing done = recv(sock, ptr, size, flags);
46236da5199SPawel Jakub Dawidek if (done == -1) {
46336da5199SPawel Jakub Dawidek if (errno == EINTR)
46436da5199SPawel Jakub Dawidek continue;
46536da5199SPawel Jakub Dawidek return (-1);
46636da5199SPawel Jakub Dawidek } else if (done == 0) {
46736da5199SPawel Jakub Dawidek errno = ENOTCONN;
46836da5199SPawel Jakub Dawidek return (-1);
46936da5199SPawel Jakub Dawidek }
47036da5199SPawel Jakub Dawidek size -= done;
47136da5199SPawel Jakub Dawidek ptr += done;
4727f7fe890SPawel Jakub Dawidek }
47336da5199SPawel Jakub Dawidek
47436da5199SPawel Jakub Dawidek return (0);
47536da5199SPawel Jakub Dawidek }
476