Distinguish UST return codes from transport return codes
[lttng-ust.git] / liblttng-ust-comm / lttng-ust-comm.c
CommitLineData
67c5b804
MD
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
15f672f9 3 * Copyright (C) 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
67c5b804 4 *
15f672f9
MD
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; only
8 * version 2.1 of the License.
9 *
10 * This library is distributed in the hope that it will be useful,
67c5b804 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15f672f9
MD
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
67c5b804
MD
18 */
19
20#define _GNU_SOURCE
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/socket.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <sys/un.h>
29#include <unistd.h>
30#include <assert.h>
57773204 31#include <errno.h>
11ba4bcb 32#include <fcntl.h>
67c5b804 33
b728d87e 34#include <ust-comm.h>
7bc53e94
MD
35#include <lttng/ust-error.h>
36
37#define USTCOMM_CODE_OFFSET(code) \
38 (code == LTTNG_UST_OK ? 0 : (code - LTTNG_UST_ERR + 1))
67c5b804
MD
39
40/*
41 * Human readable error message.
42 */
57773204 43static const char *ustcomm_readable_code[] = {
7bc53e94
MD
44 [ USTCOMM_CODE_OFFSET(LTTNG_UST_OK) ] = "Success",
45 [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR) ] = "Unknown error",
46 [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_NOENT) ] = "No entry",
67c5b804
MD
47};
48
49/*
7bc53e94 50 * lttng_ust_strerror
67c5b804 51 *
7bc53e94
MD
52 * Receives positive error value.
53 * Return ptr to string representing a human readable
54 * error code from the ustcomm_return_code enum.
67c5b804 55 */
7bc53e94 56const char *lttng_ust_strerror(int code)
67c5b804 57{
7bc53e94
MD
58 if (code == LTTNG_UST_OK)
59 return ustcomm_readable_code[USTCOMM_CODE_OFFSET(code)];
60 if (code < LTTNG_UST_ERR)
61 return strerror(code);
62 if (code >= LTTNG_UST_ERR_NR)
63 code = LTTNG_UST_ERR;
64 return ustcomm_readable_code[USTCOMM_CODE_OFFSET(code)];
65
67c5b804
MD
66}
67
68/*
57773204 69 * ustcomm_connect_unix_sock
67c5b804
MD
70 *
71 * Connect to unix socket using the path name.
72 */
57773204 73int ustcomm_connect_unix_sock(const char *pathname)
67c5b804
MD
74{
75 struct sockaddr_un sun;
7bc53e94 76 int fd, ret;
67c5b804 77
204d45df
MD
78 /*
79 * libust threads require the close-on-exec flag for all
80 * resources so it does not leak file descriptors upon exec.
81 */
11ba4bcb 82 fd = socket(PF_UNIX, SOCK_STREAM, 0);
67c5b804
MD
83 if (fd < 0) {
84 perror("socket");
7bc53e94 85 ret = -errno;
67c5b804
MD
86 goto error;
87 }
11ba4bcb
MD
88 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
89 if (ret < 0) {
90 perror("fcntl");
7bc53e94 91 ret = -errno;
11ba4bcb
MD
92 goto error_fcntl;
93 }
67c5b804
MD
94
95 memset(&sun, 0, sizeof(sun));
96 sun.sun_family = AF_UNIX;
97 strncpy(sun.sun_path, pathname, sizeof(sun.sun_path));
98 sun.sun_path[sizeof(sun.sun_path) - 1] = '\0';
99
100 ret = connect(fd, (struct sockaddr *) &sun, sizeof(sun));
101 if (ret < 0) {
102 /*
103 * Don't print message on connect error, because connect
104 * is used in normal execution to detect if sessiond is
105 * alive.
106 */
7bc53e94 107 ret = -errno;
67c5b804
MD
108 goto error_connect;
109 }
110
111 return fd;
112
113error_connect:
11ba4bcb 114error_fcntl:
7bc53e94
MD
115 {
116 int closeret;
117
118 closeret = close(fd);
119 if (closeret)
120 perror("close");
121 }
67c5b804
MD
122error:
123 return ret;
124}
125
126/*
57773204 127 * ustcomm_accept_unix_sock
67c5b804
MD
128 *
129 * Do an accept(2) on the sock and return the
130 * new file descriptor. The socket MUST be bind(2) before.
131 */
57773204 132int ustcomm_accept_unix_sock(int sock)
67c5b804
MD
133{
134 int new_fd;
135 struct sockaddr_un sun;
136 socklen_t len = 0;
137
138 /* Blocking call */
139 new_fd = accept(sock, (struct sockaddr *) &sun, &len);
140 if (new_fd < 0) {
141 perror("accept");
7bc53e94 142 return -errno;
67c5b804 143 }
67c5b804 144 return new_fd;
67c5b804
MD
145}
146
147/*
57773204 148 * ustcomm_create_unix_sock
67c5b804
MD
149 *
150 * Creates a AF_UNIX local socket using pathname
151 * bind the socket upon creation and return the fd.
152 */
57773204 153int ustcomm_create_unix_sock(const char *pathname)
67c5b804
MD
154{
155 struct sockaddr_un sun;
7bc53e94 156 int fd, ret;
67c5b804
MD
157
158 /* Create server socket */
159 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
160 perror("socket");
7bc53e94 161 ret = -errno;
67c5b804
MD
162 goto error;
163 }
164
165 memset(&sun, 0, sizeof(sun));
166 sun.sun_family = AF_UNIX;
167 strncpy(sun.sun_path, pathname, sizeof(sun.sun_path));
168 sun.sun_path[sizeof(sun.sun_path) - 1] = '\0';
169
170 /* Unlink the old file if present */
171 (void) unlink(pathname);
172 ret = bind(fd, (struct sockaddr *) &sun, sizeof(sun));
173 if (ret < 0) {
174 perror("bind");
7bc53e94
MD
175 ret = -errno;
176 goto error_close;
67c5b804
MD
177 }
178
179 return fd;
180
7bc53e94
MD
181error_close:
182 {
183 int closeret;
184
185 closeret = close(fd);
186 if (closeret) {
187 perror("close");
188 }
189 }
67c5b804
MD
190error:
191 return ret;
192}
193
194/*
57773204 195 * ustcomm_listen_unix_sock
67c5b804 196 *
e41474be 197 * Make the socket listen using LTTNG_UST_COMM_MAX_LISTEN.
67c5b804 198 */
57773204 199int ustcomm_listen_unix_sock(int sock)
67c5b804
MD
200{
201 int ret;
202
e41474be 203 ret = listen(sock, LTTNG_UST_COMM_MAX_LISTEN);
67c5b804 204 if (ret < 0) {
7bc53e94 205 ret = -errno;
67c5b804
MD
206 perror("listen");
207 }
208
209 return ret;
210}
211
212/*
57773204 213 * ustcomm_recv_unix_sock
67c5b804
MD
214 *
215 * Receive data of size len in put that data into
216 * the buf param. Using recvmsg API.
217 * Return the size of received data.
218 */
57773204 219ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len)
67c5b804 220{
913b87f1 221 struct msghdr msg;
67c5b804 222 struct iovec iov[1];
7bc53e94 223 ssize_t ret;
67c5b804 224
913b87f1
MD
225 memset(&msg, 0, sizeof(msg));
226
67c5b804
MD
227 iov[0].iov_base = buf;
228 iov[0].iov_len = len;
229 msg.msg_iov = iov;
230 msg.msg_iovlen = 1;
231
7e3cfcbe
MD
232 do {
233 ret = recvmsg(sock, &msg, 0);
234 } while (ret < 0 && errno == EINTR);
7bc53e94
MD
235
236 if (ret < 0) {
237 int shutret;
238
239 if (errno != EPIPE)
240 perror("recvmsg");
241 ret = -errno;
242
243 shutret = shutdown(sock, SHUT_RDWR);
244 if (shutret)
245 fprintf(stderr, "Socket shutdown error");
67c5b804
MD
246 }
247
248 return ret;
249}
250
251/*
57773204 252 * ustcomm_send_unix_sock
67c5b804
MD
253 *
254 * Send buf data of size len. Using sendmsg API.
255 * Return the size of sent data.
256 */
57773204 257ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len)
67c5b804 258{
913b87f1 259 struct msghdr msg;
67c5b804 260 struct iovec iov[1];
7bc53e94 261 ssize_t ret;
67c5b804 262
913b87f1
MD
263 memset(&msg, 0, sizeof(msg));
264
67c5b804
MD
265 iov[0].iov_base = buf;
266 iov[0].iov_len = len;
267 msg.msg_iov = iov;
268 msg.msg_iovlen = 1;
269
1ea11eab
MD
270 /*
271 * Using the MSG_NOSIGNAL when sending data from sessiond to
272 * libust, so libust does not receive an unhandled SIGPIPE or
273 * SIGURG. The sessiond receiver side can be made more resilient
274 * by ignoring SIGPIPE, but we don't have this luxury on the
275 * libust side.
276 */
51d9d699
MD
277 do {
278 ret = sendmsg(sock, &msg, MSG_NOSIGNAL);
279 } while (ret < 0 && errno == EINTR);
7bc53e94
MD
280
281 if (ret < 0) {
282 int shutret;
283
284 if (errno != EPIPE)
285 perror("recvmsg");
286 ret = -errno;
287
288 shutret = shutdown(sock, SHUT_RDWR);
289 if (shutret)
290 fprintf(stderr, "Socket shutdown error");
67c5b804
MD
291 }
292
293 return ret;
294}
295
296/*
57773204 297 * ustcomm_close_unix_sock
67c5b804
MD
298 *
299 * Shutdown cleanly a unix socket.
300 */
57773204 301int ustcomm_close_unix_sock(int sock)
67c5b804
MD
302{
303 int ret;
304
e6973a89 305 ret = close(sock);
67c5b804 306 if (ret < 0) {
e6973a89 307 perror("close");
7bc53e94 308 ret = -errno;
67c5b804
MD
309 }
310
311 return ret;
312}
313
314/*
57773204 315 * ustcomm_send_fds_unix_sock
67c5b804
MD
316 *
317 * Send multiple fds on a unix socket.
318 */
57773204 319ssize_t ustcomm_send_fds_unix_sock(int sock, void *buf, int *fds, size_t nb_fd, size_t len)
67c5b804 320{
913b87f1 321 struct msghdr msg;
67c5b804
MD
322 struct cmsghdr *cmptr;
323 struct iovec iov[1];
324 ssize_t ret = -1;
325 unsigned int sizeof_fds = nb_fd * sizeof(int);
326 char tmp[CMSG_SPACE(sizeof_fds)];
327
913b87f1
MD
328 memset(&msg, 0, sizeof(msg));
329
67c5b804 330 /*
7bc53e94 331 * Note: we currently only support sending a single FD per
67c5b804
MD
332 * message.
333 */
334 assert(nb_fd == 1);
335
336 msg.msg_control = (caddr_t)tmp;
337 msg.msg_controllen = CMSG_LEN(sizeof_fds);
338
339 cmptr = CMSG_FIRSTHDR(&msg);
340 cmptr->cmsg_level = SOL_SOCKET;
341 cmptr->cmsg_type = SCM_RIGHTS;
342 cmptr->cmsg_len = CMSG_LEN(sizeof_fds);
343 memcpy(CMSG_DATA(cmptr), fds, sizeof_fds);
344 /* Sum of the length of all control messages in the buffer: */
345 msg.msg_controllen = cmptr->cmsg_len;
346
347 iov[0].iov_base = buf;
348 iov[0].iov_len = len;
349 msg.msg_iov = iov;
350 msg.msg_iovlen = 1;
351
51d9d699
MD
352 do {
353 ret = sendmsg(sock, &msg, MSG_NOSIGNAL);
354 } while (ret < 0 && errno == EINTR);
7bc53e94
MD
355
356 if (ret < 0) {
357 int shutret;
358
359 if (errno != EPIPE)
360 perror("recvmsg");
361 ret = -errno;
362
363 shutret = shutdown(sock, SHUT_RDWR);
364 if (shutret)
365 fprintf(stderr, "Socket shutdown error");
67c5b804
MD
366 }
367
368 return ret;
369}
57773204
MD
370
371int ustcomm_send_app_msg(int sock, struct ustcomm_ust_msg *lum)
372{
373 ssize_t len;
374
375 len = ustcomm_send_unix_sock(sock, lum, sizeof(*lum));
376 switch (len) {
377 case sizeof(*lum):
57773204 378 break;
57773204 379 default:
7bc53e94
MD
380 if (len < 0) {
381 if (len == -ECONNRESET)
382 fprintf(stderr, "remote end closed connection\n");
383 return len;
384 } else {
385 fprintf(stderr, "incorrect message size: %zd\n", len);
386 return -EINVAL;
387 }
57773204
MD
388 }
389 return 0;
390}
391
392int ustcomm_recv_app_reply(int sock, struct ustcomm_ust_reply *lur,
393 uint32_t expected_handle, uint32_t expected_cmd)
394{
395 ssize_t len;
396
397 memset(lur, 0, sizeof(*lur));
398 len = ustcomm_recv_unix_sock(sock, lur, sizeof(*lur));
399 switch (len) {
400 case 0: /* orderly shutdown */
57773204
MD
401 return -EINVAL;
402 case sizeof(*lur):
57773204 403 if (lur->handle != expected_handle) {
c1ee6c90 404 fprintf(stderr, "Unexpected result message handle\n");
57773204
MD
405 return -EINVAL;
406 }
57773204 407 if (lur->cmd != expected_cmd) {
c1ee6c90 408 fprintf(stderr, "Unexpected result message command\n");
57773204
MD
409 return -EINVAL;
410 }
7bc53e94 411 return lur->ret_code;
57773204 412 default:
7bc53e94
MD
413 if (len < 0) {
414 /* Transport level error */
415 if (len == -ECONNRESET)
416 fprintf(stderr, "remote end closed connection\n");
417 return len;
418 } else {
419 fprintf(stderr, "incorrect message size: %zd\n", len);
420 return len;
421 }
57773204
MD
422 }
423}
424
425int ustcomm_send_app_cmd(int sock,
426 struct ustcomm_ust_msg *lum,
427 struct ustcomm_ust_reply *lur)
428{
429 int ret;
430
431 ret = ustcomm_send_app_msg(sock, lum);
432 if (ret)
433 return ret;
7bc53e94 434 return ustcomm_recv_app_reply(sock, lur, lum->handle, lum->cmd);
57773204
MD
435}
436
57773204
MD
437/*
438 * Receives a single fd from socket.
439 *
7bc53e94
MD
440 * Returns negative error value on error, or file descriptor number on
441 * success.
57773204
MD
442 */
443int ustcomm_recv_fd(int sock)
444{
445 struct iovec iov[1];
446 int ret = 0;
447 int data_fd;
448 struct cmsghdr *cmsg;
449 char recv_fd[CMSG_SPACE(sizeof(int))];
913b87f1 450 struct msghdr msg;
57773204
MD
451 union {
452 unsigned char vc[4];
453 int vi;
454 } tmp;
455 int i;
456
913b87f1
MD
457 memset(&msg, 0, sizeof(msg));
458
57773204
MD
459 /* Prepare to receive the structures */
460 iov[0].iov_base = &data_fd;
461 iov[0].iov_len = sizeof(data_fd);
462 msg.msg_iov = iov;
463 msg.msg_iovlen = 1;
464 msg.msg_control = recv_fd;
465 msg.msg_controllen = sizeof(recv_fd);
466
7e3cfcbe
MD
467 do {
468 ret = recvmsg(sock, &msg, 0);
469 } while (ret < 0 && errno == EINTR);
470 if (ret < 0) {
45d35b9f
MD
471 if (errno != EPIPE) {
472 perror("recvmsg");
473 }
7bc53e94 474 ret = -errno;
57773204
MD
475 goto end;
476 }
477 if (ret != sizeof(data_fd)) {
7210fb23 478 fprintf(stderr, "Received %d bytes, expected %zd", ret, sizeof(data_fd));
7bc53e94 479 ret = -EINVAL;
57773204
MD
480 goto end;
481 }
482 cmsg = CMSG_FIRSTHDR(&msg);
483 if (!cmsg) {
c1ee6c90 484 fprintf(stderr, "Invalid control message header\n");
7bc53e94 485 ret = -EINVAL;
57773204
MD
486 goto end;
487 }
488 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
c1ee6c90 489 fprintf(stderr, "Didn't received any fd\n");
7bc53e94 490 ret = -EINVAL;
57773204
MD
491 goto end;
492 }
493 /* this is our fd */
494 for (i = 0; i < sizeof(int); i++)
495 tmp.vc[i] = CMSG_DATA(cmsg)[i];
496 ret = tmp.vi;
e55f988e
MD
497 /*
498 * Useful for fd leak debug.
499 * fprintf(stderr, "received fd %d\n", ret);
500 */
57773204 501end:
7bc53e94
MD
502 if (ret < 0) {
503 int shutret;
504
505 shutret = shutdown(sock, SHUT_RDWR);
506 if (shutret)
507 fprintf(stderr, "Socket shutdown error");
508 }
57773204
MD
509 return ret;
510}
This page took 0.047795 seconds and 4 git commands to generate.