]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libnv/msgio.c
Merge OpenSSL 1.0.1h.
[FreeBSD/FreeBSD.git] / lib / libnv / msgio.c
1 /*-
2  * Copyright (c) 2013 The FreeBSD Foundation
3  * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
4  * All rights reserved.
5  *
6  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7  * the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/types.h>
35 #include <sys/socket.h>
36
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdbool.h>
40 #include <stdint.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 #ifdef HAVE_PJDLOG
46 #include <pjdlog.h>
47 #endif
48
49 #include "common_impl.h"
50 #include "msgio.h"
51
52 #ifndef HAVE_PJDLOG
53 #include <assert.h>
54 #define PJDLOG_ASSERT(...)              assert(__VA_ARGS__)
55 #define PJDLOG_RASSERT(expr, ...)       assert(expr)
56 #define PJDLOG_ABORT(...)               abort()
57 #endif
58
59 static int
60 msghdr_add_fd(struct cmsghdr *cmsg, int fd)
61 {
62
63         PJDLOG_ASSERT(fd >= 0);
64
65         if (!fd_is_valid(fd)) {
66                 errno = EBADF;
67                 return (-1);
68         }
69
70         cmsg->cmsg_level = SOL_SOCKET;
71         cmsg->cmsg_type = SCM_RIGHTS;
72         cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
73         bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
74
75         return (0);
76 }
77
78 static int
79 msghdr_get_fd(struct cmsghdr *cmsg)
80 {
81         int fd;
82
83         if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET ||
84             cmsg->cmsg_type != SCM_RIGHTS ||
85             cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) {
86                 errno = EINVAL;
87                 return (-1);
88         }
89
90         bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd));
91 #ifndef MSG_CMSG_CLOEXEC
92         /*
93          * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the
94          * close-on-exec flag atomically, but we still want to set it for
95          * consistency.
96          */
97         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
98 #endif
99
100         return (fd);
101 }
102
103 static void
104 fd_wait(int fd, bool doread)
105 {
106         fd_set fds;
107
108         PJDLOG_ASSERT(fd >= 0);
109
110         FD_ZERO(&fds);
111         FD_SET(fd, &fds);
112         (void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds,
113             NULL, NULL);
114 }
115
116 static int
117 msg_recv(int sock, struct msghdr *msg)
118 {
119         int flags;
120
121         PJDLOG_ASSERT(sock >= 0);
122
123 #ifdef MSG_CMSG_CLOEXEC
124         flags = MSG_CMSG_CLOEXEC;
125 #else
126         flags = 0;
127 #endif
128
129         for (;;) {
130                 fd_wait(sock, true);
131                 if (recvmsg(sock, msg, flags) == -1) {
132                         if (errno == EINTR)
133                                 continue;
134                         return (-1);
135                 }
136                 break;
137         }
138
139         return (0);
140 }
141
142 static int
143 msg_send(int sock, const struct msghdr *msg)
144 {
145
146         PJDLOG_ASSERT(sock >= 0);
147
148         for (;;) {
149                 fd_wait(sock, false);
150                 if (sendmsg(sock, msg, 0) == -1) {
151                         if (errno == EINTR)
152                                 continue;
153                         return (-1);
154                 }
155                 break;
156         }
157
158         return (0);
159 }
160
161 int
162 cred_send(int sock)
163 {
164         unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
165         struct msghdr msg;
166         struct cmsghdr *cmsg;
167         struct iovec iov;
168         uint8_t dummy;
169
170         bzero(credbuf, sizeof(credbuf));
171         bzero(&msg, sizeof(msg));
172         bzero(&iov, sizeof(iov));
173
174         /*
175          * XXX: We send one byte along with the control message, because
176          *      setting msg_iov to NULL only works if this is the first
177          *      packet send over the socket. Once we send some data we
178          *      won't be able to send credentials anymore. This is most
179          *      likely a kernel bug.
180          */
181         dummy = 0;
182         iov.iov_base = &dummy;
183         iov.iov_len = sizeof(dummy);
184
185         msg.msg_iov = &iov;
186         msg.msg_iovlen = 1;
187         msg.msg_control = credbuf;
188         msg.msg_controllen = sizeof(credbuf);
189
190         cmsg = CMSG_FIRSTHDR(&msg);
191         cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
192         cmsg->cmsg_level = SOL_SOCKET;
193         cmsg->cmsg_type = SCM_CREDS;
194
195         if (msg_send(sock, &msg) == -1)
196                 return (-1);
197
198         return (0);
199 }
200
201 int
202 cred_recv(int sock, struct cmsgcred *cred)
203 {
204         unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
205         struct msghdr msg;
206         struct cmsghdr *cmsg;
207         struct iovec iov;
208         uint8_t dummy;
209
210         bzero(credbuf, sizeof(credbuf));
211         bzero(&msg, sizeof(msg));
212         bzero(&iov, sizeof(iov));
213
214         iov.iov_base = &dummy;
215         iov.iov_len = sizeof(dummy);
216
217         msg.msg_iov = &iov;
218         msg.msg_iovlen = 1;
219         msg.msg_control = credbuf;
220         msg.msg_controllen = sizeof(credbuf);
221
222         if (msg_recv(sock, &msg) == -1)
223                 return (-1);
224
225         cmsg = CMSG_FIRSTHDR(&msg);
226         if (cmsg == NULL ||
227             cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) ||
228             cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) {
229                 errno = EINVAL;
230                 return (-1);
231         }
232         bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred));
233
234         return (0);
235 }
236
237 int
238 fd_send(int sock, const int *fds, size_t nfds)
239 {
240         struct msghdr msg;
241         struct cmsghdr *cmsg;
242         unsigned int i;
243         int serrno, ret;
244
245         if (nfds == 0 || fds == NULL) {
246                 errno = EINVAL;
247                 return (-1);
248         }
249
250         bzero(&msg, sizeof(msg));
251         msg.msg_iov = NULL;
252         msg.msg_iovlen = 0;
253         msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
254         msg.msg_control = calloc(1, msg.msg_controllen);
255         if (msg.msg_control == NULL)
256                 return (-1);
257
258         ret = -1;
259
260         for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
261             i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
262                 if (msghdr_add_fd(cmsg, fds[i]) == -1)
263                         goto end;
264         }
265
266         if (msg_send(sock, &msg) == -1)
267                 goto end;
268
269         ret = 0;
270 end:
271         serrno = errno;
272         free(msg.msg_control);
273         errno = serrno;
274         return (ret);
275 }
276
277 int
278 fd_recv(int sock, int *fds, size_t nfds)
279 {
280         struct msghdr msg;
281         struct cmsghdr *cmsg;
282         unsigned int i;
283         int serrno, ret;
284
285         if (nfds == 0 || fds == NULL) {
286                 errno = EINVAL;
287                 return (-1);
288         }
289
290         bzero(&msg, sizeof(msg));
291         msg.msg_iov = NULL;
292         msg.msg_iovlen = 0;
293         msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
294         msg.msg_control = calloc(1, msg.msg_controllen);
295         if (msg.msg_control == NULL)
296                 return (-1);
297
298         ret = -1;
299
300         if (msg_recv(sock, &msg) == -1)
301                 goto end;
302
303         for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
304             i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
305                 fds[i] = msghdr_get_fd(cmsg);
306                 if (fds[i] < 0)
307                         break;
308         }
309
310         if (cmsg != NULL || i < nfds) {
311                 int fd;
312
313                 /*
314                  * We need to close all received descriptors, even if we have
315                  * different control message (eg. SCM_CREDS) in between.
316                  */
317                 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
318                     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
319                         fd = msghdr_get_fd(cmsg);
320                         if (fd >= 0)
321                                 close(fd);
322                 }
323                 errno = EINVAL;
324                 goto end;
325         }
326
327         ret = 0;
328 end:
329         serrno = errno;
330         free(msg.msg_control);
331         errno = serrno;
332         return (ret);
333 }
334
335 int
336 buf_send(int sock, void *buf, size_t size)
337 {
338         ssize_t done;
339         unsigned char *ptr;
340
341         PJDLOG_ASSERT(sock >= 0);
342         PJDLOG_ASSERT(size > 0);
343         PJDLOG_ASSERT(buf != NULL);
344
345         ptr = buf;
346         do {
347                 fd_wait(sock, false);
348                 done = send(sock, ptr, size, 0);
349                 if (done == -1) {
350                         if (errno == EINTR)
351                                 continue;
352                         return (-1);
353                 } else if (done == 0) {
354                         errno = ENOTCONN;
355                         return (-1);
356                 }
357                 size -= done;
358                 ptr += done;
359         } while (size > 0);
360
361         return (0);
362 }
363
364 int
365 buf_recv(int sock, void *buf, size_t size)
366 {
367         ssize_t done;
368         unsigned char *ptr;
369
370         PJDLOG_ASSERT(sock >= 0);
371         PJDLOG_ASSERT(buf != NULL);
372
373         ptr = buf;
374         while (size > 0) {
375                 fd_wait(sock, true);
376                 done = recv(sock, ptr, size, 0);
377                 if (done == -1) {
378                         if (errno == EINTR)
379                                 continue;
380                         return (-1);
381                 } else if (done == 0) {
382                         errno = ENOTCONN;
383                         return (-1);
384                 }
385                 size -= done;
386                 ptr += done;
387         }
388
389         return (0);
390 }