common: compile libkernel-ctl as C++
[lttng-tools.git] / src / common / sessiond-comm / sessiond-comm.c
1 /*
2 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 */
8
9 #define _LGPL_SOURCE
10 #include <limits.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 #include <inttypes.h>
18
19 #include <common/common.h>
20 #include <common/compat/errno.h>
21
22 #include "sessiond-comm.h"
23
24 /* For Unix socket */
25 #include <common/unix.h>
26 /* For Inet socket */
27 #include "inet.h"
28 /* For Inet6 socket */
29 #include "inet6.h"
30
31 #define NETWORK_TIMEOUT_ENV "LTTNG_NETWORK_SOCKET_TIMEOUT"
32
33 static struct lttcomm_net_family net_families[] = {
34 { LTTCOMM_INET, lttcomm_create_inet_sock },
35 { LTTCOMM_INET6, lttcomm_create_inet6_sock },
36 };
37
38 /*
39 * Human readable error message.
40 */
41 static const char *lttcomm_readable_code[] = {
42 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_COMMAND_SOCK_READY) ] = "consumerd command socket ready",
43 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_SUCCESS_RECV_FD) ] = "consumerd success on receiving fds",
44 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_ERROR_RECV_FD) ] = "consumerd error on receiving fds",
45 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_ERROR_RECV_CMD) ] = "consumerd error on receiving command",
46 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_POLL_ERROR) ] = "consumerd error in polling thread",
47 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_POLL_NVAL) ] = "consumerd polling on closed fd",
48 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_POLL_HUP) ] = "consumerd all fd hung up",
49 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_EXIT_SUCCESS) ] = "consumerd exiting normally",
50 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_EXIT_FAILURE) ] = "consumerd exiting on error",
51 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_OUTFD_ERROR) ] = "consumerd error opening the tracefile",
52 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_SPLICE_EBADF) ] = "consumerd splice EBADF",
53 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_SPLICE_EINVAL) ] = "consumerd splice EINVAL",
54 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_SPLICE_ENOMEM) ] = "consumerd splice ENOMEM",
55 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_SPLICE_ESPIPE) ] = "consumerd splice ESPIPE",
56 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_ENOMEM) ] = "Consumer is out of memory",
57 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_ERROR_METADATA) ] = "Error with metadata",
58 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_FATAL) ] = "Fatal error",
59 [ LTTCOMM_ERR_INDEX(LTTCOMM_CONSUMERD_RELAYD_FAIL) ] = "Error on remote relayd",
60
61 /* Last element */
62 [ LTTCOMM_ERR_INDEX(LTTCOMM_NR) ] = "Unknown error code"
63 };
64
65 static unsigned long network_timeout;
66
67 /*
68 * Return ptr to string representing a human readable error code from the
69 * lttcomm_return_code enum.
70 *
71 * These code MUST be negative in other to treat that as an error value.
72 */
73 const char *lttcomm_get_readable_code(enum lttcomm_return_code code)
74 {
75 code = -code;
76
77 if (code < LTTCOMM_CONSUMERD_COMMAND_SOCK_READY || code > LTTCOMM_NR) {
78 code = LTTCOMM_NR;
79 }
80
81 return lttcomm_readable_code[LTTCOMM_ERR_INDEX(code)];
82 }
83
84 /*
85 * Create socket from an already allocated lttcomm socket structure and init
86 * sockaddr in the lttcomm sock.
87 */
88 int lttcomm_create_sock(struct lttcomm_sock *sock)
89 {
90 int ret, _sock_type, _sock_proto, domain;
91
92 LTTNG_ASSERT(sock);
93
94 domain = sock->sockaddr.type;
95 if (domain != LTTCOMM_INET && domain != LTTCOMM_INET6) {
96 ERR("Create socket of unknown domain %d", domain);
97 ret = -1;
98 goto error;
99 }
100
101 switch (sock->proto) {
102 case LTTCOMM_SOCK_UDP:
103 _sock_type = SOCK_DGRAM;
104 _sock_proto = IPPROTO_UDP;
105 break;
106 case LTTCOMM_SOCK_TCP:
107 _sock_type = SOCK_STREAM;
108 _sock_proto = IPPROTO_TCP;
109 break;
110 default:
111 ret = -1;
112 goto error;
113 }
114
115 ret = net_families[domain].create(sock, _sock_type, _sock_proto);
116 if (ret < 0) {
117 goto error;
118 }
119
120 error:
121 return ret;
122 }
123
124 /*
125 * Return allocated lttcomm socket structure.
126 */
127 struct lttcomm_sock *lttcomm_alloc_sock(enum lttcomm_sock_proto proto)
128 {
129 struct lttcomm_sock *sock;
130
131 sock = zmalloc(sizeof(struct lttcomm_sock));
132 if (sock == NULL) {
133 PERROR("zmalloc create sock");
134 goto end;
135 }
136
137 sock->proto = proto;
138 sock->fd = -1;
139
140 end:
141 return sock;
142 }
143
144 /*
145 * Return an allocated lttcomm socket structure and copy src content into
146 * the newly created socket.
147 *
148 * This is mostly useful when lttcomm_sock are passed between process where the
149 * fd and ops have to be changed within the correct address space.
150 */
151 struct lttcomm_sock *lttcomm_alloc_copy_sock(struct lttcomm_sock *src)
152 {
153 struct lttcomm_sock *sock;
154
155 /* Safety net */
156 LTTNG_ASSERT(src);
157
158 sock = lttcomm_alloc_sock(src->proto);
159 if (sock == NULL) {
160 goto alloc_error;
161 }
162
163 lttcomm_copy_sock(sock, src);
164
165 alloc_error:
166 return sock;
167 }
168
169 /*
170 * Create and copy socket from an allocated lttcomm socket structure.
171 *
172 * This is mostly useful when lttcomm_sock are passed between process where the
173 * fd and ops have to be changed within the correct address space.
174 */
175 void lttcomm_copy_sock(struct lttcomm_sock *dst, struct lttcomm_sock *src)
176 {
177 /* Safety net */
178 LTTNG_ASSERT(dst);
179 LTTNG_ASSERT(src);
180
181 dst->proto = src->proto;
182 dst->fd = src->fd;
183 dst->ops = src->ops;
184 /* Copy sockaddr information from original socket */
185 memcpy(&dst->sockaddr, &src->sockaddr, sizeof(dst->sockaddr));
186 }
187
188 /*
189 * Init IPv4 sockaddr structure.
190 */
191 int lttcomm_init_inet_sockaddr(struct lttcomm_sockaddr *sockaddr,
192 const char *ip, unsigned int port)
193 {
194 int ret;
195
196 LTTNG_ASSERT(sockaddr);
197 LTTNG_ASSERT(ip);
198 LTTNG_ASSERT(port > 0 && port <= 65535);
199
200 memset(sockaddr, 0, sizeof(struct lttcomm_sockaddr));
201
202 sockaddr->type = LTTCOMM_INET;
203 sockaddr->addr.sin.sin_family = AF_INET;
204 sockaddr->addr.sin.sin_port = htons(port);
205 ret = inet_pton(sockaddr->addr.sin.sin_family, ip,
206 &sockaddr->addr.sin.sin_addr);
207 if (ret < 1) {
208 ret = -1;
209 ERR("%s with port %d: unrecognized IPv4 address", ip, port);
210 goto error;
211 }
212 memset(sockaddr->addr.sin.sin_zero, 0, sizeof(sockaddr->addr.sin.sin_zero));
213
214 error:
215 return ret;
216 }
217
218 /*
219 * Init IPv6 sockaddr structure.
220 */
221 int lttcomm_init_inet6_sockaddr(struct lttcomm_sockaddr *sockaddr,
222 const char *ip, unsigned int port)
223 {
224 int ret;
225
226 LTTNG_ASSERT(sockaddr);
227 LTTNG_ASSERT(ip);
228 LTTNG_ASSERT(port > 0 && port <= 65535);
229
230 memset(sockaddr, 0, sizeof(struct lttcomm_sockaddr));
231
232 sockaddr->type = LTTCOMM_INET6;
233 sockaddr->addr.sin6.sin6_family = AF_INET6;
234 sockaddr->addr.sin6.sin6_port = htons(port);
235 ret = inet_pton(sockaddr->addr.sin6.sin6_family, ip,
236 &sockaddr->addr.sin6.sin6_addr);
237 if (ret < 1) {
238 ret = -1;
239 goto error;
240 }
241
242 error:
243 return ret;
244 }
245
246 /*
247 * Return allocated lttcomm socket structure from lttng URI.
248 */
249 struct lttcomm_sock *lttcomm_alloc_sock_from_uri(struct lttng_uri *uri)
250 {
251 int ret;
252 int _sock_proto;
253 struct lttcomm_sock *sock = NULL;
254
255 /* Safety net */
256 LTTNG_ASSERT(uri);
257
258 /* Check URI protocol */
259 if (uri->proto == LTTNG_TCP) {
260 _sock_proto = LTTCOMM_SOCK_TCP;
261 } else {
262 ERR("Relayd invalid URI proto: %d", uri->proto);
263 goto alloc_error;
264 }
265
266 sock = lttcomm_alloc_sock(_sock_proto);
267 if (sock == NULL) {
268 goto alloc_error;
269 }
270
271 /* Check destination type */
272 if (uri->dtype == LTTNG_DST_IPV4) {
273 ret = lttcomm_init_inet_sockaddr(&sock->sockaddr, uri->dst.ipv4,
274 uri->port);
275 if (ret < 0) {
276 goto error;
277 }
278 } else if (uri->dtype == LTTNG_DST_IPV6) {
279 ret = lttcomm_init_inet6_sockaddr(&sock->sockaddr, uri->dst.ipv6,
280 uri->port);
281 if (ret < 0) {
282 goto error;
283 }
284 } else {
285 /* Command URI is invalid */
286 ERR("Relayd invalid URI dst type: %d", uri->dtype);
287 goto error;
288 }
289
290 return sock;
291
292 error:
293 lttcomm_destroy_sock(sock);
294 alloc_error:
295 return NULL;
296 }
297
298 /*
299 * Destroy and free lttcomm socket.
300 */
301 void lttcomm_destroy_sock(struct lttcomm_sock *sock)
302 {
303 free(sock);
304 }
305
306 /*
307 * Allocate and return a relayd socket object using a given URI to initialize
308 * it and the major/minor version of the supported protocol.
309 *
310 * On error, NULL is returned.
311 */
312 struct lttcomm_relayd_sock *lttcomm_alloc_relayd_sock(struct lttng_uri *uri,
313 uint32_t major, uint32_t minor)
314 {
315 int ret;
316 struct lttcomm_sock *tmp_sock = NULL;
317 struct lttcomm_relayd_sock *rsock = NULL;
318
319 LTTNG_ASSERT(uri);
320
321 rsock = zmalloc(sizeof(*rsock));
322 if (!rsock) {
323 PERROR("zmalloc relayd sock");
324 goto error;
325 }
326
327 /* Allocate socket object from URI */
328 tmp_sock = lttcomm_alloc_sock_from_uri(uri);
329 if (tmp_sock == NULL) {
330 goto error_free;
331 }
332
333 /*
334 * Create socket object which basically sets the ops according to the
335 * socket protocol.
336 */
337 lttcomm_copy_sock(&rsock->sock, tmp_sock);
338 /* Temporary socket pointer not needed anymore. */
339 lttcomm_destroy_sock(tmp_sock);
340 ret = lttcomm_create_sock(&rsock->sock);
341 if (ret < 0) {
342 goto error_free;
343 }
344
345 rsock->major = major;
346 rsock->minor = minor;
347
348 return rsock;
349
350 error_free:
351 free(rsock);
352 error:
353 return NULL;
354 }
355
356 /*
357 * Set socket receiving timeout.
358 */
359 int lttcomm_setsockopt_rcv_timeout(int sock, unsigned int msec)
360 {
361 int ret;
362 struct timeval tv;
363
364 tv.tv_sec = msec / 1000;
365 tv.tv_usec = (msec % 1000) * 1000;
366
367 ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
368 if (ret < 0) {
369 PERROR("setsockopt SO_RCVTIMEO");
370 }
371
372 return ret;
373 }
374
375 /*
376 * Set socket sending timeout.
377 */
378 int lttcomm_setsockopt_snd_timeout(int sock, unsigned int msec)
379 {
380 int ret;
381 struct timeval tv;
382
383 tv.tv_sec = msec / 1000;
384 tv.tv_usec = (msec % 1000) * 1000;
385
386 ret = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
387 if (ret < 0) {
388 PERROR("setsockopt SO_SNDTIMEO");
389 }
390
391 return ret;
392 }
393
394 int lttcomm_sock_get_port(const struct lttcomm_sock *sock, uint16_t *port)
395 {
396 LTTNG_ASSERT(sock);
397 LTTNG_ASSERT(port);
398 LTTNG_ASSERT(sock->sockaddr.type == LTTCOMM_INET ||
399 sock->sockaddr.type == LTTCOMM_INET6);
400 LTTNG_ASSERT(sock->proto == LTTCOMM_SOCK_TCP ||
401 sock->proto == LTTCOMM_SOCK_UDP);
402
403 switch (sock->sockaddr.type) {
404 case LTTCOMM_INET:
405 *port = ntohs(sock->sockaddr.addr.sin.sin_port);
406 break;
407 case LTTCOMM_INET6:
408 *port = ntohs(sock->sockaddr.addr.sin6.sin6_port);
409 break;
410 default:
411 abort();
412 }
413
414 return 0;
415 }
416
417 int lttcomm_sock_set_port(struct lttcomm_sock *sock, uint16_t port)
418 {
419 LTTNG_ASSERT(sock);
420 LTTNG_ASSERT(sock->sockaddr.type == LTTCOMM_INET ||
421 sock->sockaddr.type == LTTCOMM_INET6);
422 LTTNG_ASSERT(sock->proto == LTTCOMM_SOCK_TCP ||
423 sock->proto == LTTCOMM_SOCK_UDP);
424
425 switch (sock->sockaddr.type) {
426 case LTTCOMM_INET:
427 sock->sockaddr.addr.sin.sin_port = htons(port);
428 break;
429 case LTTCOMM_INET6:
430 sock->sockaddr.addr.sin6.sin6_port = htons(port);
431 break;
432 default:
433 abort();
434 }
435
436 return 0;
437 }
438
439 void lttcomm_init(void)
440 {
441 const char *env;
442
443 env = getenv(NETWORK_TIMEOUT_ENV);
444 if (env) {
445 long timeout;
446
447 errno = 0;
448 timeout = strtol(env, NULL, 0);
449 if (errno != 0 || timeout < -1L) {
450 PERROR("Network timeout");
451 } else {
452 if (timeout > 0) {
453 network_timeout = timeout;
454 }
455 }
456 }
457 }
458
459 unsigned long lttcomm_get_network_timeout(void)
460 {
461 return network_timeout;
462 }
This page took 0.043269 seconds and 4 git commands to generate.