Fix: set app socket timeout just after accept()
[lttng-tools.git] / src / common / sessiond-comm / unix.c
CommitLineData
0d37f2bc
DG
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#define _GNU_SOURCE
20#include <assert.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28#include <errno.h>
29
90e535ef 30#include <common/common.h>
0d37f2bc
DG
31
32#include "unix.h"
33
34/*
35 * Connect to unix socket using the path name.
36 */
90e535ef 37LTTNG_HIDDEN
0d37f2bc
DG
38int lttcomm_connect_unix_sock(const char *pathname)
39{
40 struct sockaddr_un sun;
41 int fd, ret, closeret;
42
43 fd = socket(PF_UNIX, SOCK_STREAM, 0);
44 if (fd < 0) {
45 PERROR("socket");
46 ret = fd;
47 goto error;
48 }
49
50 memset(&sun, 0, sizeof(sun));
51 sun.sun_family = AF_UNIX;
52 strncpy(sun.sun_path, pathname, sizeof(sun.sun_path));
53 sun.sun_path[sizeof(sun.sun_path) - 1] = '\0';
54
55 ret = connect(fd, (struct sockaddr *) &sun, sizeof(sun));
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;
83 struct sockaddr_un sun;
84 socklen_t len = 0;
85
86 /* Blocking call */
87 new_fd = accept(sock, (struct sockaddr *) &sun, &len);
88 if (new_fd < 0) {
89 PERROR("accept");
90 }
91
92 return new_fd;
93}
94
95/*
96 * Creates a AF_UNIX local socket using pathname bind the socket upon creation
97 * and return the fd.
98 */
90e535ef 99LTTNG_HIDDEN
0d37f2bc
DG
100int lttcomm_create_unix_sock(const char *pathname)
101{
102 struct sockaddr_un sun;
103 int fd;
104 int ret = -1;
105
106 /* Create server socket */
107 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
108 PERROR("socket");
109 goto error;
110 }
111
112 memset(&sun, 0, sizeof(sun));
113 sun.sun_family = AF_UNIX;
114 strncpy(sun.sun_path, pathname, sizeof(sun.sun_path));
115 sun.sun_path[sizeof(sun.sun_path) - 1] = '\0';
116
117 /* Unlink the old file if present */
118 (void) unlink(pathname);
119 ret = bind(fd, (struct sockaddr *) &sun, sizeof(sun));
120 if (ret < 0) {
121 PERROR("bind");
122 goto error;
123 }
124
125 return fd;
126
127error:
17e75273
DG
128 if (fd >= 0) {
129 if (close(fd) < 0) {
130 PERROR("close create unix sock");
131 }
132 }
0d37f2bc
DG
133 return ret;
134}
135
136/*
137 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
138 */
90e535ef 139LTTNG_HIDDEN
0d37f2bc
DG
140int lttcomm_listen_unix_sock(int sock)
141{
142 int ret;
143
144 ret = listen(sock, LTTNG_SESSIOND_COMM_MAX_LISTEN);
145 if (ret < 0) {
146 PERROR("listen");
147 }
148
149 return ret;
150}
151
152/*
153 * Receive data of size len in put that data into the buf param. Using recvmsg
154 * API.
155 *
156 * Return the size of received data.
157 */
90e535ef 158LTTNG_HIDDEN
0d37f2bc
DG
159ssize_t lttcomm_recv_unix_sock(int sock, void *buf, size_t len)
160{
161 struct msghdr msg;
162 struct iovec iov[1];
163 ssize_t ret = -1;
7c5aef62 164 size_t len_last;
0d37f2bc
DG
165
166 memset(&msg, 0, sizeof(msg));
167
168 iov[0].iov_base = buf;
169 iov[0].iov_len = len;
170 msg.msg_iov = iov;
171 msg.msg_iovlen = 1;
172
173 do {
7c5aef62
DG
174 len_last = iov[0].iov_len;
175 ret = recvmsg(sock, &msg, 0);
176 if (ret > 0) {
177 iov[0].iov_base += ret;
178 iov[0].iov_len -= ret;
179 assert(ret <= len_last);
180 }
181 } while ((ret > 0 && ret < len_last) || (ret < 0 && errno == EINTR));
0d37f2bc
DG
182 if (ret < 0) {
183 PERROR("recvmsg");
7c5aef62
DG
184 } else if (ret > 0) {
185 ret = len;
0d37f2bc 186 }
7c5aef62 187 /* Else ret = 0 meaning an orderly shutdown. */
0d37f2bc
DG
188
189 return ret;
190}
191
192/*
193 * Send buf data of size len. Using sendmsg API.
194 *
195 * Return the size of sent data.
196 */
90e535ef 197LTTNG_HIDDEN
0d37f2bc
DG
198ssize_t lttcomm_send_unix_sock(int sock, void *buf, size_t len)
199{
200 struct msghdr msg;
201 struct iovec iov[1];
202 ssize_t ret = -1;
203
204 memset(&msg, 0, sizeof(msg));
205
206 iov[0].iov_base = buf;
207 iov[0].iov_len = len;
208 msg.msg_iov = iov;
209 msg.msg_iovlen = 1;
210
211 ret = sendmsg(sock, &msg, 0);
212 if (ret < 0) {
213 /*
214 * Only warn about EPIPE when quiet mode is deactivated.
215 * We consider EPIPE as expected.
216 */
217 if (errno != EPIPE || !lttng_opt_quiet) {
218 PERROR("sendmsg");
219 }
220 }
221
222 return ret;
223}
224
225/*
226 * Shutdown cleanly a unix socket.
227 */
90e535ef 228LTTNG_HIDDEN
0d37f2bc
DG
229int lttcomm_close_unix_sock(int sock)
230{
231 int ret, closeret;
232
233 /* Shutdown receptions and transmissions */
234 ret = shutdown(sock, SHUT_RDWR);
235 if (ret < 0) {
236 PERROR("shutdown");
237 }
238
239 closeret = close(sock);
240 if (closeret) {
241 PERROR("close");
242 }
243
244 return ret;
245}
246
247/*
248 * Send a message accompanied by fd(s) over a unix socket.
249 *
250 * Returns the size of data sent, or negative error value.
251 */
90e535ef 252LTTNG_HIDDEN
0d37f2bc
DG
253ssize_t lttcomm_send_fds_unix_sock(int sock, int *fds, size_t nb_fd)
254{
255 struct msghdr msg;
256 struct cmsghdr *cmptr;
257 struct iovec iov[1];
258 ssize_t ret = -1;
259 unsigned int sizeof_fds = nb_fd * sizeof(int);
260 char tmp[CMSG_SPACE(sizeof_fds)];
261 char dummy = 0;
262
263 memset(&msg, 0, sizeof(msg));
c617c0c6 264 memset(tmp, 0, CMSG_SPACE(sizeof_fds) * sizeof(char));
0d37f2bc
DG
265
266 if (nb_fd > LTTCOMM_MAX_SEND_FDS)
267 return -EINVAL;
268
269 msg.msg_control = (caddr_t)tmp;
270 msg.msg_controllen = CMSG_LEN(sizeof_fds);
271
272 cmptr = CMSG_FIRSTHDR(&msg);
273 cmptr->cmsg_level = SOL_SOCKET;
274 cmptr->cmsg_type = SCM_RIGHTS;
275 cmptr->cmsg_len = CMSG_LEN(sizeof_fds);
276 memcpy(CMSG_DATA(cmptr), fds, sizeof_fds);
277 /* Sum of the length of all control messages in the buffer: */
278 msg.msg_controllen = cmptr->cmsg_len;
279
280 iov[0].iov_base = &dummy;
281 iov[0].iov_len = 1;
282 msg.msg_iov = iov;
283 msg.msg_iovlen = 1;
284
285 do {
286 ret = sendmsg(sock, &msg, 0);
287 } while (ret < 0 && errno == EINTR);
288 if (ret < 0) {
289 /*
290 * Only warn about EPIPE when quiet mode is deactivated.
291 * We consider EPIPE as expected.
292 */
293 if (errno != EPIPE || !lttng_opt_quiet) {
294 PERROR("sendmsg");
295 }
296 }
297 return ret;
298}
299
300/*
301 * Recv a message accompanied by fd(s) from a unix socket.
302 *
303 * Returns the size of received data, or negative error value.
304 *
305 * Expect at most "nb_fd" file descriptors. Returns the number of fd
306 * actually received in nb_fd.
307 */
90e535ef 308LTTNG_HIDDEN
0d37f2bc
DG
309ssize_t lttcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd)
310{
311 struct iovec iov[1];
312 ssize_t ret = 0;
313 struct cmsghdr *cmsg;
314 size_t sizeof_fds = nb_fd * sizeof(int);
315 char recv_fd[CMSG_SPACE(sizeof_fds)];
316 struct msghdr msg;
317 char dummy;
318
319 memset(&msg, 0, sizeof(msg));
320
321 /* Prepare to receive the structures */
322 iov[0].iov_base = &dummy;
323 iov[0].iov_len = 1;
324 msg.msg_iov = iov;
325 msg.msg_iovlen = 1;
326 msg.msg_control = recv_fd;
327 msg.msg_controllen = sizeof(recv_fd);
328
329 do {
330 ret = recvmsg(sock, &msg, 0);
331 } while (ret < 0 && errno == EINTR);
332 if (ret < 0) {
333 PERROR("recvmsg fds");
334 goto end;
335 }
336 if (ret != 1) {
337 fprintf(stderr, "Error: Received %zd bytes, expected %d\n",
338 ret, 1);
339 goto end;
340 }
341 if (msg.msg_flags & MSG_CTRUNC) {
342 fprintf(stderr, "Error: Control message truncated.\n");
343 ret = -1;
344 goto end;
345 }
346 cmsg = CMSG_FIRSTHDR(&msg);
347 if (!cmsg) {
348 fprintf(stderr, "Error: Invalid control message header\n");
349 ret = -1;
350 goto end;
351 }
352 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
353 fprintf(stderr, "Didn't received any fd\n");
354 ret = -1;
355 goto end;
356 }
357 if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
358 fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
359 (size_t) cmsg->cmsg_len, (size_t) CMSG_LEN(sizeof_fds));
360 ret = -1;
361 goto end;
362 }
363 memcpy(fds, CMSG_DATA(cmsg), sizeof_fds);
364 ret = sizeof_fds;
365end:
366 return ret;
367}
368
369/*
370 * Send a message with credentials over a unix socket.
371 *
372 * Returns the size of data sent, or negative error value.
373 */
90e535ef 374LTTNG_HIDDEN
0d37f2bc
DG
375ssize_t lttcomm_send_creds_unix_sock(int sock, void *buf, size_t len)
376{
377 struct msghdr msg;
378 struct iovec iov[1];
379 ssize_t ret = -1;
380#ifdef __linux__
381 struct cmsghdr *cmptr;
382 size_t sizeof_cred = sizeof(lttng_sock_cred);
383 char anc_buf[CMSG_SPACE(sizeof_cred)];
384 lttng_sock_cred *creds;
385#endif /* __linux__ */
386
387 memset(&msg, 0, sizeof(msg));
c617c0c6 388 memset(anc_buf, 0, CMSG_SPACE(sizeof_cred) * sizeof(char));
0d37f2bc
DG
389
390 iov[0].iov_base = buf;
391 iov[0].iov_len = len;
392 msg.msg_iov = iov;
393 msg.msg_iovlen = 1;
394
395#ifdef __linux__
396 msg.msg_control = (caddr_t) anc_buf;
397 msg.msg_controllen = CMSG_LEN(sizeof_cred);
398
399 cmptr = CMSG_FIRSTHDR(&msg);
400 cmptr->cmsg_level = SOL_SOCKET;
401 cmptr->cmsg_type = LTTNG_SOCK_CREDS;
402 cmptr->cmsg_len = CMSG_LEN(sizeof_cred);
403
404 creds = (lttng_sock_cred*) CMSG_DATA(cmptr);
405
406 LTTNG_SOCK_SET_UID_CRED(creds, geteuid());
407 LTTNG_SOCK_SET_GID_CRED(creds, getegid());
408 LTTNG_SOCK_SET_PID_CRED(creds, getpid());
409#endif /* __linux__ */
410
411 do {
412 ret = sendmsg(sock, &msg, 0);
413 } while (ret < 0 && errno == EINTR);
414 if (ret < 0) {
415 /*
416 * Only warn about EPIPE when quiet mode is deactivated.
417 * We consider EPIPE as expected.
418 */
419 if (errno != EPIPE || !lttng_opt_quiet) {
420 PERROR("sendmsg");
421 }
422 }
423 return ret;
424}
425
426/*
427 * Recv a message accompanied with credentials from a unix socket.
428 *
429 * Returns the size of received data, or negative error value.
430 */
90e535ef 431LTTNG_HIDDEN
0d37f2bc
DG
432ssize_t lttcomm_recv_creds_unix_sock(int sock, void *buf, size_t len,
433 lttng_sock_cred *creds)
434{
435 struct msghdr msg;
436 struct iovec iov[1];
437 ssize_t ret;
438#ifdef __linux__
439 struct cmsghdr *cmptr;
440 size_t sizeof_cred = sizeof(lttng_sock_cred);
441 char anc_buf[CMSG_SPACE(sizeof_cred)];
442#endif /* __linux__ */
443
444 memset(&msg, 0, sizeof(msg));
445
446 /* Not allowed */
447 if (creds == NULL) {
448 ret = -1;
449 goto end;
450 }
451
452 /* Prepare to receive the structures */
453 iov[0].iov_base = buf;
454 iov[0].iov_len = len;
455 msg.msg_iov = iov;
456 msg.msg_iovlen = 1;
457
458#ifdef __linux__
459 msg.msg_control = anc_buf;
460 msg.msg_controllen = sizeof(anc_buf);
461#endif /* __linux__ */
462
463 do {
464 ret = recvmsg(sock, &msg, 0);
465 } while (ret < 0 && errno == EINTR);
466 if (ret < 0) {
467 PERROR("recvmsg fds");
468 goto end;
469 }
470
471#ifdef __linux__
472 if (msg.msg_flags & MSG_CTRUNC) {
473 fprintf(stderr, "Error: Control message truncated.\n");
474 ret = -1;
475 goto end;
476 }
477
478 cmptr = CMSG_FIRSTHDR(&msg);
479 if (cmptr == NULL) {
480 fprintf(stderr, "Error: Invalid control message header\n");
481 ret = -1;
482 goto end;
483 }
484
485 if (cmptr->cmsg_level != SOL_SOCKET ||
486 cmptr->cmsg_type != LTTNG_SOCK_CREDS) {
487 fprintf(stderr, "Didn't received any credentials\n");
488 ret = -1;
489 goto end;
490 }
491
492 if (cmptr->cmsg_len != CMSG_LEN(sizeof_cred)) {
493 fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
494 (size_t) cmptr->cmsg_len, (size_t) CMSG_LEN(sizeof_cred));
495 ret = -1;
496 goto end;
497 }
498
499 memcpy(creds, CMSG_DATA(cmptr), sizeof_cred);
500#elif (defined(__FreeBSD__) || defined(__CYGWIN__))
501 {
502 int peer_ret;
503
504 peer_ret = getpeereid(sock, &creds->uid, &creds->gid);
505 if (peer_ret != 0) {
506 return peer_ret;
507 }
508 }
509#else
510#error "Please implement credential support for your OS."
511#endif /* __linux__ */
512
513end:
514 return ret;
515}
516
517/*
518 * Set socket option to use credentials passing.
519 */
520#ifdef __linux__
90e535ef 521LTTNG_HIDDEN
0d37f2bc
DG
522int lttcomm_setsockopt_creds_unix_sock(int sock)
523{
524 int ret, on = 1;
525
526 /* Set socket for credentials retrieval */
527 ret = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
528 if (ret < 0) {
529 PERROR("setsockopt creds unix sock");
530 }
531 return ret;
532}
533#elif (defined(__FreeBSD__) || defined(__CYGWIN__))
90e535ef 534LTTNG_HIDDEN
0d37f2bc
DG
535int lttcomm_setsockopt_creds_unix_sock(int sock)
536{
537 return 0;
538}
539#else
540#error "Please implement credential support for your OS."
541#endif /* __linux__ */
This page took 0.072815 seconds and 4 git commands to generate.