Fix: add missing VALGRIND ifdef checks and documentation
[lttng-tools.git] / src / bin / lttng-sessiond / jul.c
CommitLineData
0475c50c
DG
1/*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _GNU_SOURCE
19#include <assert.h>
f20baf8e 20#include <urcu/uatomic.h>
0475c50c
DG
21
22#include <common/common.h>
f20baf8e 23#include <common/sessiond-comm/jul.h>
0475c50c
DG
24
25#include "jul.h"
f20baf8e 26#include "ust-app.h"
0475c50c
DG
27#include "utils.h"
28
29/*
428de77a 30 * URCU delayed JUL event reclaim.
0475c50c
DG
31 */
32static void destroy_event_jul_rcu(struct rcu_head *head)
33{
34 struct lttng_ht_node_str *node =
35 caa_container_of(head, struct lttng_ht_node_str, head);
36 struct jul_event *event =
37 caa_container_of(node, struct jul_event, node);
38
39 free(event);
40}
41
f20baf8e 42/*
428de77a 43 * URCU delayed JUL app reclaim.
f20baf8e
DG
44 */
45static void destroy_app_jul_rcu(struct rcu_head *head)
46{
47 struct lttng_ht_node_ulong *node =
48 caa_container_of(head, struct lttng_ht_node_ulong, head);
49 struct jul_app *app =
50 caa_container_of(node, struct jul_app, node);
51
52 free(app);
53}
54
55/*
428de77a
MD
56 * Communication with Java agent. Send the message header to the given
57 * socket in big endian.
f20baf8e
DG
58 *
59 * Return 0 on success or else a negative errno message of sendmsg() op.
60 */
61static int send_header(struct lttcomm_sock *sock, uint64_t data_size,
62 uint32_t cmd, uint32_t cmd_version)
63{
64 int ret;
65 ssize_t size;
66 struct lttcomm_jul_hdr msg;
67
68 assert(sock);
69
70 msg.data_size = htobe64(data_size);
71 msg.cmd = htobe32(cmd);
72 msg.cmd_version = htobe32(cmd_version);
73
74 size = sock->ops->sendmsg(sock, &msg, sizeof(msg), 0);
75 if (size < sizeof(msg)) {
76 ret = -errno;
77 goto error;
78 }
79 ret = 0;
80
81error:
82 return ret;
83}
84
85/*
86 * Communication call with the Java agent. Send the payload to the given
87 * socket. The header MUST be sent prior to this call.
88 *
89 * Return 0 on success or else a negative errno value of sendmsg() op.
90 */
91static int send_payload(struct lttcomm_sock *sock, void *data,
92 size_t size)
93{
94 int ret;
95 ssize_t len;
96
97 assert(sock);
98 assert(data);
99
100 len = sock->ops->sendmsg(sock, data, size, 0);
101 if (len < size) {
102 ret = -errno;
103 goto error;
104 }
105 ret = 0;
106
107error:
108 return ret;
109}
110
111/*
112 * Communication call with the Java agent. Receive reply from the agent using
113 * the given socket.
114 *
115 * Return 0 on success or else a negative errno value from recvmsg() op.
116 */
117static int recv_reply(struct lttcomm_sock *sock, void *buf, size_t size)
118{
119 int ret;
120 ssize_t len;
121
122 assert(sock);
123 assert(buf);
124
125 len = sock->ops->recvmsg(sock, buf, size, 0);
126 if (len < size) {
127 ret = -errno;
128 goto error;
129 }
130 ret = 0;
131
132error:
133 return ret;
134}
135
3c6a091f
DG
136
137/*
428de77a 138 * Internal event listing for a given app. Populate events.
3c6a091f
DG
139 *
140 * Return number of element in the list or else a negative LTTNG_ERR* code.
428de77a
MD
141 * On success, the caller is responsible for freeing the memory
142 * allocated for "events".
3c6a091f
DG
143 */
144static ssize_t list_events(struct jul_app *app, struct lttng_event **events)
145{
146 int ret, i, len = 0, offset = 0;
147 uint32_t nb_event;
148 size_t data_size;
149 struct lttng_event *tmp_events = NULL;
150 struct lttcomm_jul_list_reply *reply = NULL;
151 struct lttcomm_jul_list_reply_hdr reply_hdr;
152
153 assert(app);
154 assert(app->sock);
155 assert(events);
156
157 DBG2("JUL listing events for app pid: %d and socket %d", app->pid,
158 app->sock->fd);
159
160 ret = send_header(app->sock, 0, JUL_CMD_LIST, 0);
161 if (ret < 0) {
162 goto error_io;
163 }
164
165 /* Get list header so we know how much we'll receive. */
166 ret = recv_reply(app->sock, &reply_hdr, sizeof(reply_hdr));
167 if (ret < 0) {
168 goto error_io;
169 }
170
171 switch (be32toh(reply_hdr.ret_code)) {
172 case JUL_RET_CODE_SUCCESS:
173 data_size = be32toh(reply_hdr.data_size) + sizeof(*reply);
174 break;
175 default:
176 ERR("Java agent returned an unknown code: %" PRIu32,
177 be32toh(reply_hdr.ret_code));
178 ret = LTTNG_ERR_FATAL;
179 goto error;
180 }
181
182 reply = zmalloc(data_size);
183 if (!reply) {
184 ret = LTTNG_ERR_NOMEM;
185 goto error;
186 }
187
188 /* Get the list with the appropriate data size. */
189 ret = recv_reply(app->sock, reply, data_size);
190 if (ret < 0) {
191 goto error_io;
192 }
193
194 nb_event = be32toh(reply->nb_event);
195 tmp_events = zmalloc(sizeof(*tmp_events) * nb_event);
196 if (!tmp_events) {
197 ret = LTTNG_ERR_NOMEM;
198 goto error;
199 }
200
201 for (i = 0; i < nb_event; i++) {
202 offset += len;
203 strncpy(tmp_events[i].name, reply->payload + offset,
204 sizeof(tmp_events[i].name));
205 tmp_events[i].pid = app->pid;
206 tmp_events[i].enabled = -1;
207 len = strlen(reply->payload + offset) + 1;
208 }
209
210 *events = tmp_events;
211
212 free(reply);
213 return nb_event;
214
215error_io:
216 ret = LTTNG_ERR_UST_LIST_FAIL;
217error:
218 free(reply);
219 free(tmp_events);
220 return -ret;
221
222}
223
f20baf8e 224/*
428de77a 225 * Internal enable JUL event on a JUL application. This function
f20baf8e
DG
226 * communicates with the Java agent to enable a given event (Logger name).
227 *
228 * Return LTTNG_OK on success or else a LTTNG_ERR* code.
229 */
230static int enable_event(struct jul_app *app, struct jul_event *event)
231{
232 int ret;
233 uint64_t data_size;
234 struct lttcomm_jul_enable msg;
235 struct lttcomm_jul_generic_reply reply;
236
237 assert(app);
238 assert(app->sock);
239 assert(event);
240
241 DBG2("JUL enabling event %s for app pid: %d and socket %d", event->name,
242 app->pid, app->sock->fd);
243
244 data_size = sizeof(msg);
245
246 ret = send_header(app->sock, data_size, JUL_CMD_ENABLE, 0);
247 if (ret < 0) {
248 goto error_io;
249 }
250
b2064f54
DG
251 msg.loglevel = event->loglevel;
252 msg.loglevel_type = event->loglevel_type;
f20baf8e
DG
253 strncpy(msg.name, event->name, sizeof(msg.name));
254 ret = send_payload(app->sock, &msg, sizeof(msg));
255 if (ret < 0) {
256 goto error_io;
257 }
258
259 ret = recv_reply(app->sock, &reply, sizeof(reply));
260 if (ret < 0) {
261 goto error_io;
262 }
263
264 switch (be32toh(reply.ret_code)) {
265 case JUL_RET_CODE_SUCCESS:
266 break;
267 case JUL_RET_CODE_UNKNOWN_NAME:
268 ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
269 goto error;
270 default:
271 ERR("Java agent returned an unknown code: %" PRIu32,
272 be32toh(reply.ret_code));
273 ret = LTTNG_ERR_FATAL;
274 goto error;
275 }
276
277 return LTTNG_OK;
278
279error_io:
280 ret = LTTNG_ERR_UST_ENABLE_FAIL;
281error:
282 return ret;
283}
284
285/*
286 * Internal disable JUL event call on a JUL application. This function
287 * communicates with the Java agent to disable a given event (Logger name).
288 *
289 * Return LTTNG_OK on success or else a LTTNG_ERR* code.
290 */
291static int disable_event(struct jul_app *app, struct jul_event *event)
292{
293 int ret;
294 uint64_t data_size;
295 struct lttcomm_jul_disable msg;
296 struct lttcomm_jul_generic_reply reply;
297
298 assert(app);
299 assert(app->sock);
300 assert(event);
301
302 DBG2("JUL disabling event %s for app pid: %d and socket %d", event->name,
303 app->pid, app->sock->fd);
304
305 data_size = sizeof(msg);
306
307 ret = send_header(app->sock, data_size, JUL_CMD_DISABLE, 0);
308 if (ret < 0) {
309 goto error_io;
310 }
311
312 strncpy(msg.name, event->name, sizeof(msg.name));
313 ret = send_payload(app->sock, &msg, sizeof(msg));
314 if (ret < 0) {
315 goto error_io;
316 }
317
318 ret = recv_reply(app->sock, &reply, sizeof(reply));
319 if (ret < 0) {
320 goto error_io;
321 }
322
323 switch (be32toh(reply.ret_code)) {
324 case JUL_RET_CODE_SUCCESS:
325 break;
326 case JUL_RET_CODE_UNKNOWN_NAME:
327 ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
328 goto error;
329 default:
330 ERR("Java agent returned an unknown code: %" PRIu32,
331 be32toh(reply.ret_code));
332 ret = LTTNG_ERR_FATAL;
333 goto error;
334 }
335
336 return LTTNG_OK;
337
338error_io:
339 ret = LTTNG_ERR_UST_DISABLE_FAIL;
340error:
341 return ret;
342}
343
344/*
345 * Enable JUL event on every JUL applications registered with the session
346 * daemon.
347 *
348 * Return LTTNG_OK on success or else a LTTNG_ERR* code.
349 */
350int jul_enable_event(struct jul_event *event)
351{
352 int ret;
353 struct jul_app *app;
354 struct lttng_ht_iter iter;
355
356 assert(event);
357
358 rcu_read_lock();
359
360 cds_lfht_for_each_entry(jul_apps_ht_by_sock->ht, &iter.iter, app,
361 node.node) {
362 /* Enable event on JUL application through TCP socket. */
363 ret = enable_event(app, event);
364 if (ret != LTTNG_OK) {
365 goto error;
366 }
f20baf8e
DG
367 }
368
3c6a091f 369 event->enabled = 1;
f20baf8e
DG
370 ret = LTTNG_OK;
371
372error:
373 rcu_read_unlock();
374 return ret;
375}
376
377/*
378 * Disable JUL event on every JUL applications registered with the session
379 * daemon.
380 *
381 * Return LTTNG_OK on success or else a LTTNG_ERR* code.
382 */
383int jul_disable_event(struct jul_event *event)
384{
385 int ret;
386 struct jul_app *app;
387 struct lttng_ht_iter iter;
388
389 assert(event);
390
391 rcu_read_lock();
392
393 cds_lfht_for_each_entry(jul_apps_ht_by_sock->ht, &iter.iter, app,
394 node.node) {
395 /* Enable event on JUL application through TCP socket. */
396 ret = disable_event(app, event);
397 if (ret != LTTNG_OK) {
398 goto error;
399 }
f20baf8e
DG
400 }
401
3c6a091f 402 event->enabled = 0;
f20baf8e
DG
403 ret = LTTNG_OK;
404
405error:
406 rcu_read_unlock();
407 return ret;
408}
409
410/*
411 * Ask every java agent for the list of possible event (logger name). Events is
412 * allocated with the events of every JUL application.
413 *
414 * Return the number of events or else a negative value.
415 */
416int jul_list_events(struct lttng_event **events)
417{
418 int ret;
419 size_t nbmem, count = 0;
420 struct jul_app *app;
aae6255e 421 struct lttng_event *tmp_events = NULL;
f20baf8e
DG
422 struct lttng_ht_iter iter;
423
424 assert(events);
425
426 nbmem = UST_APP_EVENT_LIST_SIZE;
427 tmp_events = zmalloc(nbmem * sizeof(*tmp_events));
428 if (!tmp_events) {
429 PERROR("zmalloc jul list events");
430 ret = -ENOMEM;
431 goto error;
432 }
433
434 rcu_read_lock();
435 cds_lfht_for_each_entry(jul_apps_ht_by_sock->ht, &iter.iter, app,
436 node.node) {
437 ssize_t nb_ev;
438 struct lttng_event *jul_events;
439
440 nb_ev = list_events(app, &jul_events);
441 if (nb_ev < 0) {
442 ret = nb_ev;
428de77a 443 goto error_unlock;
f20baf8e
DG
444 }
445
446 if (count >= nbmem) {
447 /* In case the realloc fails, we free the memory */
448 void *ptr;
449
450 DBG2("Reallocating JUL event list from %zu to %zu entries", nbmem,
451 2 * nbmem);
452 nbmem *= 2;
453 ptr = realloc(tmp_events, nbmem * sizeof(*tmp_events));
454 if (!ptr) {
455 PERROR("realloc JUL events");
f20baf8e 456 ret = -ENOMEM;
c36441a9 457 free(jul_events);
428de77a 458 goto error_unlock;
f20baf8e
DG
459 }
460 tmp_events = ptr;
461 }
462 memcpy(tmp_events + (count * sizeof(*tmp_events)), jul_events,
463 nb_ev * sizeof(*tmp_events));
464 free(jul_events);
465 count += nb_ev;
466 }
467 rcu_read_unlock();
468
469 ret = count;
470 *events = tmp_events;
aae6255e 471 return ret;
f20baf8e 472
428de77a
MD
473error_unlock:
474 rcu_read_unlock();
f20baf8e 475error:
aae6255e 476 free(tmp_events);
f20baf8e
DG
477 return ret;
478}
479
480/*
481 * Create a JUL app object using the given PID.
482 *
483 * Return newly allocated object or else NULL on error.
484 */
485struct jul_app *jul_create_app(pid_t pid, struct lttcomm_sock *sock)
486{
487 struct jul_app *app;
488
489 assert(sock);
490
491 app = zmalloc(sizeof(*app));
492 if (!app) {
493 PERROR("zmalloc JUL create");
494 goto error;
495 }
496
497 app->pid = pid;
498 app->sock = sock;
f20baf8e
DG
499 lttng_ht_node_init_ulong(&app->node, (unsigned long) app->sock->fd);
500
501error:
502 return app;
503}
504
505/*
506 * Lookup JUL app by socket in the global hash table.
507 *
508 * RCU read side lock MUST be acquired.
509 *
510 * Return object if found else NULL.
511 */
512struct jul_app *jul_find_app_by_sock(int sock)
513{
514 struct lttng_ht_node_ulong *node;
515 struct lttng_ht_iter iter;
516 struct jul_app *app;
517
518 assert(sock >= 0);
519
520 lttng_ht_lookup(jul_apps_ht_by_sock, (void *)((unsigned long) sock), &iter);
521 node = lttng_ht_iter_get_node_ulong(&iter);
522 if (node == NULL) {
523 goto error;
524 }
525 app = caa_container_of(node, struct jul_app, node);
526
527 DBG3("JUL app pid %d found by sock %d.", app->pid, sock);
528 return app;
529
530error:
531 DBG3("JUL app NOT found by sock %d.", sock);
532 return NULL;
533}
534
535/*
536 * Add JUL application object to a given hash table.
537 */
538void jul_add_app(struct jul_app *app)
539{
540 assert(app);
541
542 DBG3("JUL adding app sock: %d and pid: %d to ht", app->sock->fd, app->pid);
543
544 rcu_read_lock();
545 lttng_ht_add_unique_ulong(jul_apps_ht_by_sock, &app->node);
546 rcu_read_unlock();
547}
548
f20baf8e
DG
549/*
550 * Delete JUL application from the global hash table.
551 */
552void jul_delete_app(struct jul_app *app)
553{
554 int ret;
555 struct lttng_ht_iter iter;
556
557 assert(app);
558
559 DBG3("JUL deleting app pid: %d and sock: %d", app->pid, app->sock->fd);
560
561 iter.iter.node = &app->node.node;
562 rcu_read_lock();
563 ret = lttng_ht_del(jul_apps_ht_by_sock, &iter);
564 rcu_read_unlock();
565 assert(!ret);
566}
567
568/*
569 * Destroy a JUL application object by detaching it from its corresponding UST
428de77a
MD
570 * app if one is connected by closing the socket. Finally, perform a
571 * delayed memory reclaim.
f20baf8e
DG
572 */
573void jul_destroy_app(struct jul_app *app)
574{
575 assert(app);
576
577 if (app->sock) {
578 app->sock->ops->close(app->sock);
579 lttcomm_destroy_sock(app->sock);
580 }
581
582 call_rcu(&app->node.head, destroy_app_jul_rcu);
583}
584
0475c50c
DG
585/*
586 * Initialize an already allocated JUL domain object.
587 *
588 * Return 0 on success or else a negative errno value.
589 */
590int jul_init_domain(struct jul_domain *dom)
591{
592 int ret;
593
594 assert(dom);
595
596 dom->events = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
597 if (!dom->events) {
598 ret = -ENOMEM;
599 goto error;
600 }
601
602 return 0;
603
604error:
605 return ret;
606}
607
608/*
609 * Create a newly allocated JUL event data structure. If name is valid, it's
610 * copied into the created event.
611 *
612 * Return a new object else NULL on error.
613 */
614struct jul_event *jul_create_event(const char *name)
615{
616 struct jul_event *event;
617
618 DBG3("JUL create new event with name %s", name);
619
620 event = zmalloc(sizeof(*event));
621 if (!event) {
622 goto error;
623 }
624
625 if (name) {
626 strncpy(event->name, name, sizeof(event->name));
627 event->name[sizeof(event->name) - 1] = '\0';
f20baf8e 628 lttng_ht_node_init_str(&event->node, event->name);
0475c50c
DG
629 }
630
631error:
632 return event;
633}
634
635/*
636 * Unique add of a JUL event to a given domain.
637 */
638void jul_add_event(struct jul_event *event, struct jul_domain *dom)
639{
640 assert(event);
641 assert(dom);
642 assert(dom->events);
643
644 DBG3("JUL adding event %s to domain", event->name);
645
f20baf8e 646 rcu_read_lock();
0475c50c 647 lttng_ht_add_unique_str(dom->events, &event->node);
f20baf8e 648 rcu_read_unlock();
3c6a091f 649 dom->being_used = 1;
0475c50c
DG
650}
651
652/*
653 * Find a JUL event in the given domain using name.
654 *
655 * RCU read side lock MUST be acquired.
656 *
657 * Return object if found else NULL.
658 */
659struct jul_event *jul_find_by_name(const char *name, struct jul_domain *dom)
660{
661 struct lttng_ht_node_str *node;
662 struct lttng_ht_iter iter;
663
664 assert(name);
665 assert(dom);
666 assert(dom->events);
667
668 lttng_ht_lookup(dom->events, (void *)name, &iter);
669 node = lttng_ht_iter_get_node_str(&iter);
670 if (node == NULL) {
671 goto error;
672 }
673
674 DBG3("JUL found by name %s in domain.", name);
675 return caa_container_of(node, struct jul_event, node);
676
677error:
678 DBG3("JUL NOT found by name %s in domain.", name);
679 return NULL;
680}
681
0475c50c 682/*
428de77a
MD
683 * Free given JUL event. This event must not be globally visible at this
684 * point (only expected to be used on failure just after event
685 * creation). After this call, the pointer is not usable anymore.
0475c50c
DG
686 */
687void jul_destroy_event(struct jul_event *event)
688{
689 assert(event);
690
691 free(event);
692}
693
694/*
695 * Destroy a JUL domain completely. Note that the given pointer is NOT freed
428de77a 696 * thus a reference to static or stack data can be passed to this function.
0475c50c
DG
697 */
698void jul_destroy_domain(struct jul_domain *dom)
699{
700 struct lttng_ht_node_str *node;
701 struct lttng_ht_iter iter;
702
703 assert(dom);
704
705 DBG3("JUL destroy domain");
706
707 /*
708 * Just ignore if no events hash table exists. This is possible if for
709 * instance a JUL domain object was allocated but not initialized.
710 */
711 if (!dom->events) {
712 return;
713 }
714
715 rcu_read_lock();
716 cds_lfht_for_each_entry(dom->events->ht, &iter.iter, node, node) {
717 int ret;
718
719 ret = lttng_ht_del(dom->events, &iter);
720 assert(!ret);
721 call_rcu(&node->head, destroy_event_jul_rcu);
722 }
723 rcu_read_unlock();
724
f20baf8e
DG
725 lttng_ht_destroy(dom->events);
726}
727
728/*
729 * Initialize JUL subsystem.
730 */
731int jul_init(void)
732{
733 jul_apps_ht_by_sock = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
734 if (!jul_apps_ht_by_sock) {
735 return -1;
736 }
737
738 return 0;
739}
740
741/*
742 * Update a JUL application (given socket) using the given domain.
743 *
744 * Note that this function is most likely to be used with a tracing session
745 * thus the caller should make sure to hold the appropriate lock(s).
746 */
747void jul_update(struct jul_domain *domain, int sock)
748{
749 int ret;
750 struct jul_app *app;
751 struct jul_event *event;
752 struct lttng_ht_iter iter;
753
754 assert(domain);
755 assert(sock >= 0);
756
757 DBG("JUL updating app socket %d", sock);
758
759 rcu_read_lock();
760 cds_lfht_for_each_entry(domain->events->ht, &iter.iter, event, node.node) {
761 /* Skip event if disabled. */
762 if (!event->enabled) {
763 continue;
764 }
765
766 app = jul_find_app_by_sock(sock);
767 /*
768 * We are in the registration path thus if the application is gone,
769 * there is a serious code flow error.
770 */
771 assert(app);
772
773 ret = enable_event(app, event);
774 if (ret != LTTNG_OK) {
775 DBG2("JUL update unable to enable event %s on app pid: %d sock %d",
776 event->name, app->pid, app->sock->fd);
777 /* Let's try the others here and don't assume the app is dead. */
778 continue;
779 }
780 }
781 rcu_read_unlock();
0475c50c 782}
This page took 0.086381 seconds and 4 git commands to generate.