payload: use fd_handle instead of raw file descriptors
[lttng-tools.git] / src / common / unix.c
CommitLineData
0d37f2bc 1/*
ab5be9fa
MJ
2 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
0d37f2bc 4 *
ab5be9fa 5 * SPDX-License-Identifier: GPL-2.0-only
0d37f2bc 6 *
0d37f2bc
DG
7 */
8
6c1c0768 9#define _LGPL_SOURCE
0d37f2bc
DG
10#include <assert.h>
11#include <limits.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/stat.h>
16#include <sys/types.h>
17#include <unistd.h>
18#include <errno.h>
19
90e535ef 20#include <common/common.h>
2038dd6c 21#include <common/sessiond-comm/sessiond-comm.h>
fe489250 22#include <common/fd-handle.h>
0d37f2bc
DG
23
24#include "unix.h"
25
26/*
27 * Connect to unix socket using the path name.
28 */
90e535ef 29LTTNG_HIDDEN
0d37f2bc
DG
30int lttcomm_connect_unix_sock(const char *pathname)
31{
665886a6 32 struct sockaddr_un s_un;
0d37f2bc
DG
33 int fd, ret, closeret;
34
7f8bf467
JG
35 if (strlen(pathname) >= sizeof(s_un.sun_path)) {
36 ERR("unix socket address (\"%s\") is longer than the platform's limit (%zu > %zu).",
37 pathname, strlen(pathname) + 1,
38 sizeof(s_un.sun_path));
39 ret = -ENAMETOOLONG;
40 goto error;
41 }
42
0d37f2bc
DG
43 fd = socket(PF_UNIX, SOCK_STREAM, 0);
44 if (fd < 0) {
45 PERROR("socket");
46 ret = fd;
47 goto error;
48 }
49
665886a6
MJ
50 memset(&s_un, 0, sizeof(s_un));
51 s_un.sun_family = AF_UNIX;
52 strncpy(s_un.sun_path, pathname, sizeof(s_un.sun_path));
53 s_un.sun_path[sizeof(s_un.sun_path) - 1] = '\0';
0d37f2bc 54
665886a6 55 ret = connect(fd, (struct sockaddr *) &s_un, sizeof(s_un));
0d37f2bc
DG
56 if (ret < 0) {
57 /*
58 * Don't print message on connect error, because connect is used in
59 * normal execution to detect if sessiond is alive.
60 */
61 goto error_connect;
62 }
63
64 return fd;
65
66error_connect:
67 closeret = close(fd);
68 if (closeret) {
69 PERROR("close");
70 }
71error:
72 return ret;
73}
74
75/*
76 * Do an accept(2) on the sock and return the new file descriptor. The socket
77 * MUST be bind(2) before.
78 */
90e535ef 79LTTNG_HIDDEN
0d37f2bc
DG
80int lttcomm_accept_unix_sock(int sock)
81{
82 int new_fd;
665886a6 83 struct sockaddr_un s_un;
50786a72 84 socklen_t len = sizeof(s_un);
0d37f2bc
DG
85
86 /* Blocking call */
665886a6 87 new_fd = accept(sock, (struct sockaddr *) &s_un, &len);
0d37f2bc
DG
88 if (new_fd < 0) {
89 PERROR("accept");
90 }
91
92 return new_fd;
93}
94
7567352f
MD
95LTTNG_HIDDEN
96int lttcomm_create_anon_unix_socketpair(int *fds)
97{
98 if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) < 0) {
99 PERROR("socketpair");
100 return -1;
101 }
102 return 0;
103}
104
0d37f2bc
DG
105/*
106 * Creates a AF_UNIX local socket using pathname bind the socket upon creation
107 * and return the fd.
108 */
90e535ef 109LTTNG_HIDDEN
0d37f2bc
DG
110int lttcomm_create_unix_sock(const char *pathname)
111{
665886a6 112 struct sockaddr_un s_un;
7f8bf467 113 int fd = -1;
0d37f2bc
DG
114 int ret = -1;
115
7f8bf467
JG
116 if (strlen(pathname) >= sizeof(s_un.sun_path)) {
117 ERR("unix socket address (\"%s\") is longer than the platform's limit (%zu > %zu).",
118 pathname, strlen(pathname) + 1,
119 sizeof(s_un.sun_path));
120 ret = -ENAMETOOLONG;
121 goto error;
122 }
123
0d37f2bc
DG
124 /* Create server socket */
125 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
126 PERROR("socket");
127 goto error;
128 }
129
665886a6
MJ
130 memset(&s_un, 0, sizeof(s_un));
131 s_un.sun_family = AF_UNIX;
132 strncpy(s_un.sun_path, pathname, sizeof(s_un.sun_path));
133 s_un.sun_path[sizeof(s_un.sun_path) - 1] = '\0';
0d37f2bc
DG
134
135 /* Unlink the old file if present */
136 (void) unlink(pathname);
665886a6 137 ret = bind(fd, (struct sockaddr *) &s_un, sizeof(s_un));
0d37f2bc
DG
138 if (ret < 0) {
139 PERROR("bind");
140 goto error;
141 }
142
143 return fd;
144
145error:
17e75273
DG
146 if (fd >= 0) {
147 if (close(fd) < 0) {
148 PERROR("close create unix sock");
149 }
150 }
0d37f2bc
DG
151 return ret;
152}
153
154/*
155 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
156 */
90e535ef 157LTTNG_HIDDEN
0d37f2bc
DG
158int lttcomm_listen_unix_sock(int sock)
159{
160 int ret;
161
162 ret = listen(sock, LTTNG_SESSIOND_COMM_MAX_LISTEN);
163 if (ret < 0) {
164 PERROR("listen");
165 }
166
167 return ret;
168}
169
170/*
171 * Receive data of size len in put that data into the buf param. Using recvmsg
172 * API.
173 *
174 * Return the size of received data.
175 */
90e535ef 176LTTNG_HIDDEN
0d37f2bc
DG
177ssize_t lttcomm_recv_unix_sock(int sock, void *buf, size_t len)
178{
179 struct msghdr msg;
180 struct iovec iov[1];
181 ssize_t ret = -1;
7c5aef62 182 size_t len_last;
0d37f2bc
DG
183
184 memset(&msg, 0, sizeof(msg));
185
186 iov[0].iov_base = buf;
187 iov[0].iov_len = len;
188 msg.msg_iov = iov;
189 msg.msg_iovlen = 1;
190
191 do {
7c5aef62 192 len_last = iov[0].iov_len;
fbb1fd3a 193 ret = lttng_recvmsg_nosigpipe(sock, &msg);
7c5aef62
DG
194 if (ret > 0) {
195 iov[0].iov_base += ret;
196 iov[0].iov_len -= ret;
197 assert(ret <= len_last);
198 }
199 } while ((ret > 0 && ret < len_last) || (ret < 0 && errno == EINTR));
0d37f2bc
DG
200 if (ret < 0) {
201 PERROR("recvmsg");
7c5aef62
DG
202 } else if (ret > 0) {
203 ret = len;
0d37f2bc 204 }
7c5aef62 205 /* Else ret = 0 meaning an orderly shutdown. */
0d37f2bc
DG
206
207 return ret;
208}
209
c72435ad
JG
210/*
211 * Receive data of size len in put that data into the buf param. Using recvmsg
212 * API. Only use with sockets set in non-blocking mode.
213 *
44c180ca
JR
214 * NOTE: EPIPE errors are NOT reported. This call expects the socket to be in a
215 * poll set. The poll loop will handle the EPIPE original cause.
216 *
c72435ad
JG
217 * Return the size of received data.
218 */
219LTTNG_HIDDEN
220ssize_t lttcomm_recv_unix_sock_non_block(int sock, void *buf, size_t len)
221{
222 struct msghdr msg;
223 struct iovec iov[1];
224 ssize_t ret;
225
226 memset(&msg, 0, sizeof(msg));
227
228 iov[0].iov_base = buf;
229 iov[0].iov_len = len;
230 msg.msg_iov = iov;
231 msg.msg_iovlen = 1;
232
233retry:
234 ret = lttng_recvmsg_nosigpipe(sock, &msg);
235 if (ret < 0) {
236 if (errno == EINTR) {
237 goto retry;
238 } else {
44c180ca
JR
239 /*
240 * We consider EPIPE and EAGAIN/EWOULDBLOCK as expected.
241 */
242 if (errno == EAGAIN || errno == EWOULDBLOCK ||
243 errno == EPIPE) {
244 /*
245 * Nothing was recv.
246 */
247 ret = 0;
248 goto end;
c72435ad 249 }
44c180ca
JR
250
251 /* Unexpected error */
252 PERROR("recvmsg");
253 ret = -1;
c72435ad
JG
254 goto end;
255 }
256 }
5b86bd5e 257
c72435ad
JG
258end:
259 return ret;
260}
261
0d37f2bc
DG
262/*
263 * Send buf data of size len. Using sendmsg API.
264 *
265 * Return the size of sent data.
266 */
90e535ef 267LTTNG_HIDDEN
c2d69327 268ssize_t lttcomm_send_unix_sock(int sock, const void *buf, size_t len)
0d37f2bc
DG
269{
270 struct msghdr msg;
271 struct iovec iov[1];
c72435ad 272 ssize_t ret;
0d37f2bc
DG
273
274 memset(&msg, 0, sizeof(msg));
275
c2d69327 276 iov[0].iov_base = (void *) buf;
0d37f2bc
DG
277 iov[0].iov_len = len;
278 msg.msg_iov = iov;
279 msg.msg_iovlen = 1;
280
c72435ad
JG
281 while (iov[0].iov_len) {
282 ret = sendmsg(sock, &msg, 0);
283 if (ret < 0) {
284 if (errno == EINTR) {
285 continue;
286 } else {
287 /*
288 * Only warn about EPIPE when quiet mode is
289 * deactivated.
290 * We consider EPIPE as expected.
291 */
292 if (errno != EPIPE || !lttng_opt_quiet) {
293 PERROR("sendmsg");
294 }
295 goto end;
296 }
297 }
298 iov[0].iov_len -= ret;
299 iov[0].iov_base += ret;
300 }
301 ret = len;
302end:
303 return ret;
304}
305
306/*
307 * Send buf data of size len. Using sendmsg API.
308 * Only use with non-blocking sockets. The difference with the blocking version
309 * of the function is that this one does not retry to send on partial sends,
310 * except if the interruption was caused by a signal (EINTR).
311 *
44c180ca
JR
312 * NOTE: EPIPE errors are NOT reported. This call expects the socket to be in a
313 * poll set. The poll loop will handle the EPIPE original cause.
314 *
c72435ad
JG
315 * Return the size of sent data.
316 */
317LTTNG_HIDDEN
318ssize_t lttcomm_send_unix_sock_non_block(int sock, const void *buf, size_t len)
319{
320 struct msghdr msg;
321 struct iovec iov[1];
322 ssize_t ret;
323
324 memset(&msg, 0, sizeof(msg));
325
326 iov[0].iov_base = (void *) buf;
327 iov[0].iov_len = len;
328 msg.msg_iov = iov;
329 msg.msg_iovlen = 1;
330
331retry:
0d37f2bc
DG
332 ret = sendmsg(sock, &msg, 0);
333 if (ret < 0) {
c72435ad
JG
334 if (errno == EINTR) {
335 goto retry;
336 } else {
44c180ca
JR
337 /*
338 * We consider EPIPE and EAGAIN/EWOULDBLOCK as expected.
339 */
340 if (errno == EAGAIN || errno == EWOULDBLOCK ||
341 errno == EPIPE) {
342 /*
343 * This can happen in non blocking mode.
344 * Nothing was sent.
345 */
346 ret = 0;
347 goto end;
c72435ad 348 }
44c180ca
JR
349
350 /* Unexpected error */
351 PERROR("sendmsg");
352 ret = -1;
c72435ad 353 goto end;
0d37f2bc
DG
354 }
355 }
c72435ad 356end:
0d37f2bc
DG
357 return ret;
358}
359
360/*
361 * Shutdown cleanly a unix socket.
362 */
90e535ef 363LTTNG_HIDDEN
0d37f2bc
DG
364int lttcomm_close_unix_sock(int sock)
365{
366 int ret, closeret;
367
368 /* Shutdown receptions and transmissions */
369 ret = shutdown(sock, SHUT_RDWR);
370 if (ret < 0) {
371 PERROR("shutdown");
372 }
373
374 closeret = close(sock);
375 if (closeret) {
376 PERROR("close");
377 }
378
379 return ret;
380}
381
382/*
383 * Send a message accompanied by fd(s) over a unix socket.
384 *
385 * Returns the size of data sent, or negative error value.
386 */
90e535ef 387LTTNG_HIDDEN
ac2f30af 388ssize_t lttcomm_send_fds_unix_sock(int sock, const int *fds, size_t nb_fd)
0d37f2bc
DG
389{
390 struct msghdr msg;
391 struct cmsghdr *cmptr;
392 struct iovec iov[1];
393 ssize_t ret = -1;
394 unsigned int sizeof_fds = nb_fd * sizeof(int);
395 char tmp[CMSG_SPACE(sizeof_fds)];
396 char dummy = 0;
397
398 memset(&msg, 0, sizeof(msg));
b3f35e02 399 memset(tmp, 0, sizeof(tmp));
0d37f2bc
DG
400
401 if (nb_fd > LTTCOMM_MAX_SEND_FDS)
402 return -EINVAL;
403
404 msg.msg_control = (caddr_t)tmp;
405 msg.msg_controllen = CMSG_LEN(sizeof_fds);
406
407 cmptr = CMSG_FIRSTHDR(&msg);
1d8d0328
MJ
408 if (!cmptr) {
409 return -1;
410 }
b3f35e02 411
0d37f2bc
DG
412 cmptr->cmsg_level = SOL_SOCKET;
413 cmptr->cmsg_type = SCM_RIGHTS;
414 cmptr->cmsg_len = CMSG_LEN(sizeof_fds);
415 memcpy(CMSG_DATA(cmptr), fds, sizeof_fds);
416 /* Sum of the length of all control messages in the buffer: */
417 msg.msg_controllen = cmptr->cmsg_len;
418
419 iov[0].iov_base = &dummy;
420 iov[0].iov_len = 1;
421 msg.msg_iov = iov;
422 msg.msg_iovlen = 1;
423
424 do {
425 ret = sendmsg(sock, &msg, 0);
426 } while (ret < 0 && errno == EINTR);
427 if (ret < 0) {
428 /*
429 * Only warn about EPIPE when quiet mode is deactivated.
430 * We consider EPIPE as expected.
431 */
432 if (errno != EPIPE || !lttng_opt_quiet) {
433 PERROR("sendmsg");
434 }
435 }
436 return ret;
437}
438
fe489250
JG
439/*
440 * Send the fd(s) of a payload view over a unix socket.
441 *
442 * Returns the size of data sent, or negative error value.
443 */
444static
445ssize_t _lttcomm_send_payload_view_fds_unix_sock(int sock,
446 struct lttng_payload_view *view,
447 bool blocking)
448{
449 int i;
450 ssize_t ret;
451 struct lttng_dynamic_array raw_fds;
452 const int fd_count = lttng_payload_view_get_fd_handle_count(view);
453
454 lttng_dynamic_array_init(&raw_fds, sizeof(int), NULL);
455
456 /*
457 * Prepare a contiguous array of file descriptors to send them.
458 *
459 * Note that the reference to each fd is released during the iteration;
460 * we're just getting the numerical value of the fds to conform to the
461 * syscall's interface. We rely on the fact that "view" must remain
462 * valid for the duration of the call and that the underlying payload
463 * owns a reference to the fd_handles.
464 */
465 for (i = 0; i < fd_count; i++) {
466 struct fd_handle *handle =
467 lttng_payload_view_pop_fd_handle(view);
468 const int raw_fd = fd_handle_get_fd(handle);
469 const int add_ret = lttng_dynamic_array_add_element(
470 &raw_fds, &raw_fd);
471
472 fd_handle_put(handle);
473 if (add_ret) {
474 ret = -LTTNG_ERR_NOMEM;
475 goto end;
476 }
477 }
478
479 if (blocking) {
480 ret = lttcomm_send_fds_unix_sock(sock,
481 (const int *) raw_fds.buffer.data, fd_count);
482 } else {
483 ret = lttcomm_send_fds_unix_sock_non_block(sock,
484 (const int *) raw_fds.buffer.data, fd_count);
485 }
486
487end:
488 lttng_dynamic_array_reset(&raw_fds);
489 return ret;
490}
491
492LTTNG_HIDDEN
493ssize_t lttcomm_send_payload_view_fds_unix_sock(int sock,
494 struct lttng_payload_view *view)
495{
496 return _lttcomm_send_payload_view_fds_unix_sock(sock, view, true);
497}
498
499LTTNG_HIDDEN
500ssize_t lttcomm_send_payload_view_fds_unix_sock_non_block(int sock,
501 struct lttng_payload_view *view)
502{
503 return _lttcomm_send_payload_view_fds_unix_sock(sock, view, false);
504}
505
b72ce630
JR
506/*
507 * Send a message accompanied by fd(s) over a unix socket.
508 * Only use for non blocking socket.
509 *
510 * Returns the size of data sent, or negative error value.
511 */
512LTTNG_HIDDEN
513ssize_t lttcomm_send_fds_unix_sock_non_block(int sock, const int *fds, size_t nb_fd)
514{
515 struct msghdr msg;
516 struct cmsghdr *cmptr;
517 struct iovec iov[1];
518 ssize_t ret = -1;
519 unsigned int sizeof_fds = nb_fd * sizeof(int);
520 char tmp[CMSG_SPACE(sizeof_fds)];
521 char dummy = 0;
522
523 memset(&msg, 0, sizeof(msg));
524 memset(tmp, 0, sizeof(tmp));
525
526 if (nb_fd > LTTCOMM_MAX_SEND_FDS)
527 return -EINVAL;
528
529 msg.msg_control = (caddr_t)tmp;
530 msg.msg_controllen = CMSG_LEN(sizeof_fds);
531
532 cmptr = CMSG_FIRSTHDR(&msg);
533 if (!cmptr) {
534 return -1;
535 }
536
537 cmptr->cmsg_level = SOL_SOCKET;
538 cmptr->cmsg_type = SCM_RIGHTS;
539 cmptr->cmsg_len = CMSG_LEN(sizeof_fds);
540 memcpy(CMSG_DATA(cmptr), fds, sizeof_fds);
541 /* Sum of the length of all control messages in the buffer: */
542 msg.msg_controllen = cmptr->cmsg_len;
543
544 iov[0].iov_base = &dummy;
545 iov[0].iov_len = 1;
546 msg.msg_iov = iov;
547 msg.msg_iovlen = 1;
548
549retry:
550 ret = sendmsg(sock, &msg, 0);
551 if (ret < 0) {
552 if (errno == EINTR) {
553 goto retry;
554 } else {
555 /*
556 * We consider EPIPE and EAGAIN/EWOULDBLOCK as expected.
557 */
558 if (errno == EAGAIN || errno == EWOULDBLOCK) {
559 /*
560 * This can happen in non blocking mode.
561 * Nothing was sent.
562 */
563 ret = 0;
564 goto end;
565 }
566
567 if (errno == EPIPE) {
568 /* Expected error, pass error to caller */
569 DBG3("EPIPE on sendmsg");
570 ret = -1;
571 goto end;
572 }
573
574 /* Unexpected error */
575 PERROR("sendmsg");
576 ret = -1;
577 goto end;
578 }
579 }
580
581end:
582 return ret;
583}
584
0d37f2bc
DG
585/*
586 * Recv a message accompanied by fd(s) from a unix socket.
587 *
588 * Returns the size of received data, or negative error value.
589 *
590 * Expect at most "nb_fd" file descriptors. Returns the number of fd
591 * actually received in nb_fd.
592 */
90e535ef 593LTTNG_HIDDEN
0d37f2bc
DG
594ssize_t lttcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd)
595{
596 struct iovec iov[1];
597 ssize_t ret = 0;
598 struct cmsghdr *cmsg;
599 size_t sizeof_fds = nb_fd * sizeof(int);
b3f35e02 600
ba49ae8c
MJ
601#ifdef __linux__
602/* Account for the struct ucred cmsg in the buffer size */
603#define LTTNG_SOCK_RECV_FDS_BUF_SIZE CMSG_SPACE(sizeof_fds) + CMSG_SPACE(sizeof(struct ucred))
604#else
605#define LTTNG_SOCK_RECV_FDS_BUF_SIZE CMSG_SPACE(sizeof_fds)
606#endif /* __linux__ */
607
608 char recv_buf[LTTNG_SOCK_RECV_FDS_BUF_SIZE];
0d37f2bc
DG
609 struct msghdr msg;
610 char dummy;
611
612 memset(&msg, 0, sizeof(msg));
613
614 /* Prepare to receive the structures */
615 iov[0].iov_base = &dummy;
616 iov[0].iov_len = 1;
617 msg.msg_iov = iov;
618 msg.msg_iovlen = 1;
b3f35e02
FD
619
620 cmsg = (struct cmsghdr *) recv_buf;
621 cmsg->cmsg_len = CMSG_LEN(sizeof_fds);
622 cmsg->cmsg_level = SOL_SOCKET;
623 cmsg->cmsg_type = SCM_RIGHTS;
624
625 msg.msg_control = cmsg;
626 msg.msg_controllen = CMSG_LEN(sizeof(recv_buf));
627 msg.msg_flags = 0;
0d37f2bc 628
b72ce630
JR
629retry:
630 ret = lttng_recvmsg_nosigpipe(sock, &msg);
0d37f2bc 631 if (ret < 0) {
b72ce630
JR
632 if (errno == EINTR) {
633 goto retry;
634 } else {
635 /* We consider EPIPE and EAGAIN as expected. */
636 if (!lttng_opt_quiet &&
637 (errno != EPIPE && errno != EAGAIN)) {
638 PERROR("recvmsg");
639 }
640 goto end;
641 }
642 }
643
644 if (ret != 1) {
645 fprintf(stderr, "Error: Received %zd bytes, expected %d\n",
646 ret, 1);
0d37f2bc
DG
647 goto end;
648 }
b3f35e02 649
b72ce630
JR
650 if (msg.msg_flags & MSG_CTRUNC) {
651 fprintf(stderr, "Error: Control message truncated.\n");
652 ret = -1;
653 goto end;
654 }
655
656 /*
657 * If the socket was configured with SO_PASSCRED, the kernel will add a
658 * control message (cmsg) to the ancillary data of the unix socket. We
659 * need to expect a cmsg of the SCM_CREDENTIALS as the first control
660 * message.
661 */
662 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
663 if (cmsg->cmsg_level != SOL_SOCKET) {
664 fprintf(stderr, "Error: The socket needs to be of type SOL_SOCKET\n");
665 ret = -1;
666 goto end;
667 }
668 if (cmsg->cmsg_type == SCM_RIGHTS) {
669 /*
670 * We found the controle message for file descriptors,
671 * now copy the fds to the fds ptr and return success.
672 */
673 if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
674 fprintf(stderr, "Error: Received %zu bytes of"
675 "ancillary data for FDs, expected %zu\n",
676 (size_t) cmsg->cmsg_len,
677 (size_t) CMSG_LEN(sizeof_fds));
678 ret = -1;
679 goto end;
680 }
681 memcpy(fds, CMSG_DATA(cmsg), sizeof_fds);
682 ret = sizeof_fds;
683 goto end;
684 }
685#ifdef __linux__
686 if (cmsg->cmsg_type == SCM_CREDENTIALS) {
687 /*
688 * Expect credentials to be sent when expecting fds even
689 * if no credential were include in the send(). The
690 * kernel adds them...
691 */
692 ret = -1;
693 }
694#endif /* __linux__ */
695 }
696end:
697 return ret;
698}
699
fe489250
JG
700static
701void close_raw_fd(void *ptr)
702{
703 const int raw_fd = *((const int *) ptr);
704
705 if (raw_fd >= 0) {
706 const int ret = close(raw_fd);
707
708 if (ret) {
709 PERROR("Failed to close file descriptor %d", raw_fd);
710 }
711 }
712}
713
714static
715enum lttng_error_code add_fds_to_payload(struct lttng_dynamic_array *raw_fds,
716 struct lttng_payload *payload)
717{
718 int i;
719 enum lttng_error_code ret_code = LTTNG_OK;
720 const int fd_count = lttng_dynamic_array_get_count(raw_fds);
721
722 for (i = 0; i < fd_count; i++) {
723 int ret;
724 struct fd_handle *handle;
725 int *raw_fd = (int *) lttng_dynamic_array_get_element(
726 raw_fds, i);
727
728 handle = fd_handle_create(*raw_fd);
729 if (!handle) {
730 ret_code = LTTNG_ERR_NOMEM;
731 goto end;
732 }
733
734 /* FD ownership transferred to the handle. */
735 *raw_fd = -1;
736
737 ret = lttng_payload_push_fd_handle(payload, handle);
738 fd_handle_put(handle);
739 if (ret) {
740 ret_code = LTTNG_ERR_NOMEM;
741 goto end;
742 }
743 }
744
745end:
746 return ret_code;
747}
748
749static
750ssize_t _lttcomm_recv_payload_fds_unix_sock(int sock, size_t nb_fd,
751 struct lttng_payload *payload, bool blocking)
752{
753 enum lttng_error_code add_ret;
754 ssize_t ret;
755 struct lttng_dynamic_array raw_fds;
756
757 lttng_dynamic_array_init(&raw_fds, sizeof(int), close_raw_fd);
758 ret = lttng_dynamic_array_set_count(&raw_fds, nb_fd);
759 if (ret) {
760 ret = -LTTNG_ERR_NOMEM;
761 goto end;
762 }
763
764 if (blocking) {
765 ret = lttcomm_recv_fds_unix_sock(
766 sock, (int *) raw_fds.buffer.data, nb_fd);
767 } else {
768 ret = lttcomm_recv_fds_unix_sock_non_block(
769 sock, (int *) raw_fds.buffer.data, nb_fd);
770 }
771
772 if (ret < 0) {
773 goto end;
774 }
775
776 add_ret = add_fds_to_payload(&raw_fds, payload);
777 if (add_ret != LTTNG_OK) {
778 ret = - (int) add_ret;
779 goto end;
780 }
781
782end:
783 lttng_dynamic_array_reset(&raw_fds);
784 return ret;
785}
786
787LTTNG_HIDDEN
788ssize_t lttcomm_recv_payload_fds_unix_sock(int sock, size_t nb_fd,
789 struct lttng_payload *payload)
790{
791 return _lttcomm_recv_payload_fds_unix_sock(sock, nb_fd, payload, true);
792}
793
794LTTNG_HIDDEN
795ssize_t lttcomm_recv_payload_fds_unix_sock_non_block(int sock, size_t nb_fd,
796 struct lttng_payload *payload)
797{
798 return _lttcomm_recv_payload_fds_unix_sock(sock, nb_fd, payload, false);
799}
800
b72ce630
JR
801/*
802 * Recv a message accompanied by fd(s) from a non-blocking unix socket.
803 * Only use with non-blocking sockets.
804 *
805 * Returns the size of received data, or negative error value.
806 *
807 * Expect at most "nb_fd" file descriptors.
808 *
809 * Note that based on our comprehension, partial reception of fds is not
810 * possible since the FDs are actually in the control message. It is all or
811 * nothing, still the sender side can send the wrong number of fds.
812 */
813LTTNG_HIDDEN
814ssize_t lttcomm_recv_fds_unix_sock_non_block(int sock, int *fds, size_t nb_fd)
815{
816 struct iovec iov[1];
817 ssize_t ret = 0;
818 struct cmsghdr *cmsg;
819 size_t sizeof_fds = nb_fd * sizeof(int);
820
821#ifdef __linux__
822/* Account for the struct ucred cmsg in the buffer size */
823#define LTTNG_SOCK_RECV_FDS_BUF_SIZE CMSG_SPACE(sizeof_fds) + CMSG_SPACE(sizeof(struct ucred))
824#else
825#define LTTNG_SOCK_RECV_FDS_BUF_SIZE CMSG_SPACE(sizeof_fds)
826#endif /* __linux__ */
827
828 char recv_buf[LTTNG_SOCK_RECV_FDS_BUF_SIZE];
829 struct msghdr msg;
830 char dummy;
831
832 memset(&msg, 0, sizeof(msg));
833
834 /* Prepare to receive the structures */
835 iov[0].iov_base = &dummy;
836 iov[0].iov_len = 1;
837 msg.msg_iov = iov;
838 msg.msg_iovlen = 1;
839
840 cmsg = (struct cmsghdr *) recv_buf;
841 cmsg->cmsg_len = CMSG_LEN(sizeof_fds);
842 cmsg->cmsg_level = SOL_SOCKET;
843 cmsg->cmsg_type = SCM_RIGHTS;
844
845 msg.msg_control = cmsg;
846 msg.msg_controllen = CMSG_LEN(sizeof(recv_buf));
847 msg.msg_flags = 0;
848
849retry:
850 ret = lttng_recvmsg_nosigpipe(sock, &msg);
851 if (ret < 0) {
852 if (errno == EINTR) {
853 goto retry;
854 } else {
855 /*
856 * We consider EPIPE and EAGAIN/EWOULDBLOCK as expected.
857 */
858 if (errno == EAGAIN || errno == EWOULDBLOCK) {
859 /*
860 * This can happen in non blocking mode.
861 * Nothing was recv.
862 */
863 ret = 0;
864 goto end;
865 }
866
867 if (errno == EPIPE) {
868 /* Expected error, pass error to caller */
869 DBG3("EPIPE on recvmsg");
870 ret = -1;
871 goto end;
872 }
873
874 /* Unexpected error */
875 PERROR("recvmsg");
876 ret = -1;
877 goto end;
878 }
879 }
880
0d37f2bc
DG
881 if (ret != 1) {
882 fprintf(stderr, "Error: Received %zd bytes, expected %d\n",
883 ret, 1);
884 goto end;
885 }
b3f35e02 886
0d37f2bc
DG
887 if (msg.msg_flags & MSG_CTRUNC) {
888 fprintf(stderr, "Error: Control message truncated.\n");
889 ret = -1;
890 goto end;
891 }
b3f35e02
FD
892
893 /*
894 * If the socket was configured with SO_PASSCRED, the kernel will add a
895 * control message (cmsg) to the ancillary data of the unix socket. We
896 * need to expect a cmsg of the SCM_CREDENTIALS as the first control
897 * message.
898 */
899 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
b3f35e02
FD
900 if (cmsg->cmsg_level != SOL_SOCKET) {
901 fprintf(stderr, "Error: The socket needs to be of type SOL_SOCKET\n");
902 ret = -1;
903 goto end;
904 }
905 if (cmsg->cmsg_type == SCM_RIGHTS) {
906 /*
907 * We found the controle message for file descriptors,
908 * now copy the fds to the fds ptr and return success.
909 */
910 if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
911 fprintf(stderr, "Error: Received %zu bytes of"
912 "ancillary data for FDs, expected %zu\n",
913 (size_t) cmsg->cmsg_len,
914 (size_t) CMSG_LEN(sizeof_fds));
915 ret = -1;
916 goto end;
917 }
918 memcpy(fds, CMSG_DATA(cmsg), sizeof_fds);
919 ret = sizeof_fds;
920 goto end;
921 }
ba49ae8c 922#ifdef __linux__
b3f35e02
FD
923 if (cmsg->cmsg_type == SCM_CREDENTIALS) {
924 /*
925 * Expect credentials to be sent when expecting fds even
926 * if no credential were include in the send(). The
927 * kernel adds them...
928 */
b3f35e02
FD
929 ret = -1;
930 }
ba49ae8c 931#endif /* __linux__ */
0d37f2bc 932 }
0d37f2bc
DG
933end:
934 return ret;
935}
936
937/*
938 * Send a message with credentials over a unix socket.
939 *
940 * Returns the size of data sent, or negative error value.
941 */
90e535ef 942LTTNG_HIDDEN
e368fb43 943ssize_t lttcomm_send_creds_unix_sock(int sock, const void *buf, size_t len)
0d37f2bc
DG
944{
945 struct msghdr msg;
946 struct iovec iov[1];
947 ssize_t ret = -1;
948#ifdef __linux__
949 struct cmsghdr *cmptr;
950 size_t sizeof_cred = sizeof(lttng_sock_cred);
951 char anc_buf[CMSG_SPACE(sizeof_cred)];
952 lttng_sock_cred *creds;
8bbffd54
MJ
953
954 memset(anc_buf, 0, CMSG_SPACE(sizeof_cred) * sizeof(char));
0d37f2bc
DG
955#endif /* __linux__ */
956
957 memset(&msg, 0, sizeof(msg));
958
e368fb43 959 iov[0].iov_base = (void *) buf;
0d37f2bc
DG
960 iov[0].iov_len = len;
961 msg.msg_iov = iov;
962 msg.msg_iovlen = 1;
963
964#ifdef __linux__
965 msg.msg_control = (caddr_t) anc_buf;
966 msg.msg_controllen = CMSG_LEN(sizeof_cred);
967
968 cmptr = CMSG_FIRSTHDR(&msg);
1d8d0328
MJ
969 if (!cmptr) {
970 return -1;
971 }
0d37f2bc
DG
972 cmptr->cmsg_level = SOL_SOCKET;
973 cmptr->cmsg_type = LTTNG_SOCK_CREDS;
974 cmptr->cmsg_len = CMSG_LEN(sizeof_cred);
975
976 creds = (lttng_sock_cred*) CMSG_DATA(cmptr);
977
978 LTTNG_SOCK_SET_UID_CRED(creds, geteuid());
979 LTTNG_SOCK_SET_GID_CRED(creds, getegid());
980 LTTNG_SOCK_SET_PID_CRED(creds, getpid());
981#endif /* __linux__ */
982
983 do {
984 ret = sendmsg(sock, &msg, 0);
985 } while (ret < 0 && errno == EINTR);
986 if (ret < 0) {
987 /*
988 * Only warn about EPIPE when quiet mode is deactivated.
989 * We consider EPIPE as expected.
990 */
991 if (errno != EPIPE || !lttng_opt_quiet) {
992 PERROR("sendmsg");
993 }
994 }
995 return ret;
996}
997
998/*
999 * Recv a message accompanied with credentials from a unix socket.
1000 *
1001 * Returns the size of received data, or negative error value.
1002 */
90e535ef 1003LTTNG_HIDDEN
0d37f2bc
DG
1004ssize_t lttcomm_recv_creds_unix_sock(int sock, void *buf, size_t len,
1005 lttng_sock_cred *creds)
1006{
1007 struct msghdr msg;
1008 struct iovec iov[1];
1009 ssize_t ret;
4100e49a 1010 size_t len_last;
0d37f2bc
DG
1011#ifdef __linux__
1012 struct cmsghdr *cmptr;
1013 size_t sizeof_cred = sizeof(lttng_sock_cred);
1014 char anc_buf[CMSG_SPACE(sizeof_cred)];
1015#endif /* __linux__ */
1016
1017 memset(&msg, 0, sizeof(msg));
1018
1019 /* Not allowed */
1020 if (creds == NULL) {
1021 ret = -1;
1022 goto end;
1023 }
1024
1025 /* Prepare to receive the structures */
1026 iov[0].iov_base = buf;
1027 iov[0].iov_len = len;
1028 msg.msg_iov = iov;
1029 msg.msg_iovlen = 1;
1030
1031#ifdef __linux__
1032 msg.msg_control = anc_buf;
1033 msg.msg_controllen = sizeof(anc_buf);
1034#endif /* __linux__ */
1035
1036 do {
4100e49a 1037 len_last = iov[0].iov_len;
0d37f2bc 1038 ret = recvmsg(sock, &msg, 0);
4100e49a
DG
1039 if (ret > 0) {
1040 iov[0].iov_base += ret;
1041 iov[0].iov_len -= ret;
1042 assert(ret <= len_last);
1043 }
1044 } while ((ret > 0 && ret < len_last) || (ret < 0 && errno == EINTR));
0d37f2bc
DG
1045 if (ret < 0) {
1046 PERROR("recvmsg fds");
1047 goto end;
4100e49a
DG
1048 } else if (ret > 0) {
1049 ret = len;
0d37f2bc 1050 }
4100e49a 1051 /* Else ret = 0 meaning an orderly shutdown. */
0d37f2bc
DG
1052
1053#ifdef __linux__
1054 if (msg.msg_flags & MSG_CTRUNC) {
1055 fprintf(stderr, "Error: Control message truncated.\n");
1056 ret = -1;
1057 goto end;
1058 }
1059
1060 cmptr = CMSG_FIRSTHDR(&msg);
1061 if (cmptr == NULL) {
1062 fprintf(stderr, "Error: Invalid control message header\n");
1063 ret = -1;
1064 goto end;
1065 }
1066
1067 if (cmptr->cmsg_level != SOL_SOCKET ||
1068 cmptr->cmsg_type != LTTNG_SOCK_CREDS) {
1069 fprintf(stderr, "Didn't received any credentials\n");
1070 ret = -1;
1071 goto end;
1072 }
1073
1074 if (cmptr->cmsg_len != CMSG_LEN(sizeof_cred)) {
1075 fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
1076 (size_t) cmptr->cmsg_len, (size_t) CMSG_LEN(sizeof_cred));
1077 ret = -1;
1078 goto end;
1079 }
1080
1081 memcpy(creds, CMSG_DATA(cmptr), sizeof_cred);
bfa419e4 1082#elif (defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__sun__) || defined(__APPLE__))
0d37f2bc
DG
1083 {
1084 int peer_ret;
1085
1086 peer_ret = getpeereid(sock, &creds->uid, &creds->gid);
1087 if (peer_ret != 0) {
1088 return peer_ret;
1089 }
1090 }
1091#else
1092#error "Please implement credential support for your OS."
1093#endif /* __linux__ */
1094
1095end:
1096 return ret;
1097}
1098
1099/*
1100 * Set socket option to use credentials passing.
1101 */
1102#ifdef __linux__
90e535ef 1103LTTNG_HIDDEN
0d37f2bc
DG
1104int lttcomm_setsockopt_creds_unix_sock(int sock)
1105{
1106 int ret, on = 1;
1107
1108 /* Set socket for credentials retrieval */
1109 ret = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
1110 if (ret < 0) {
1111 PERROR("setsockopt creds unix sock");
1112 }
1113 return ret;
1114}
bfa419e4 1115#elif (defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__sun__) || defined(__APPLE__))
90e535ef 1116LTTNG_HIDDEN
0d37f2bc
DG
1117int lttcomm_setsockopt_creds_unix_sock(int sock)
1118{
1119 return 0;
1120}
1121#else
1122#error "Please implement credential support for your OS."
1123#endif /* __linux__ */
This page took 0.159161 seconds and 4 git commands to generate.