actions: list: Add `for_each_action_{const, mutable}()` macros
[lttng-tools.git] / tests / regression / tools / trigger / utils / notification-client.cpp
CommitLineData
6ba31891
FD
1/*
2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
28f23191
JG
8#include "utils.h"
9
2460203a 10#include <lttng/action/list-internal.hpp>
28f23191
JG
11#include <lttng/condition/event-rule-matches.h>
12#include <lttng/lttng.h>
13
6ba31891
FD
14#include <getopt.h>
15#include <stdbool.h>
16#include <stddef.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/time.h>
21#include <time.h>
22
28f23191 23static struct option long_options[] = {
6ba31891 24 /* These options set a flag. */
28f23191
JG
25 { "trigger", required_argument, 0, 't' },
26 { "sync-after-notif-register", required_argument, 0, 'a' },
6ffce1f5 27 /* Default alue for count is 1 */
28f23191 28 { "count", required_argument, 0, 'b' },
6ffce1f5
JR
29 /*
30 * When end-trigger is present the reception loop is exited only when a
31 * notification matching the end trigger is received.
32 * Otherwise the loop is exited when the count of notification received
33 * for `trigger` math the `count` argument.
34 */
28f23191
JG
35 { "end-trigger", required_argument, 0, 'c' },
36 { 0, 0, 0, 0 }
6ba31891
FD
37};
38
28f23191 39static bool action_list_contains_notify(const struct lttng_action *action_list)
6ba31891 40{
2460203a 41 const struct lttng_action *sub_action;
6ba31891 42
2460203a
FD
43 for_each_action_const (sub_action, action_list) {
44 if (lttng_action_get_type(sub_action) == LTTNG_ACTION_TYPE_NOTIFY) {
6ba31891
FD
45 return true;
46 }
47 }
48 return false;
49}
50
0efb2ad7 51/* Only expects named triggers. */
7d59def2 52static bool is_trigger_name(const char *expected_trigger_name,
28f23191 53 struct lttng_notification *notification)
6ba31891 54{
65f64978
JG
55 const char *trigger_name = NULL;
56 enum lttng_trigger_status trigger_status;
57 const struct lttng_trigger *trigger;
58 bool names_match;
6ba31891 59
65f64978
JG
60 trigger = lttng_notification_get_trigger(notification);
61 if (!trigger) {
62 fprintf(stderr, "Failed to get trigger from notification\n");
63 names_match = false;
64 goto end;
6ba31891 65 }
65f64978
JG
66
67 trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
68 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
69 fprintf(stderr, "Failed to get name from notification's trigger\n");
70 names_match = false;
71 goto end;
6ba31891
FD
72 }
73
65f64978 74 names_match = strcmp(expected_trigger_name, trigger_name) == 0;
7d59def2 75 if (!names_match) {
28f23191
JG
76 fprintf(stderr,
77 "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
78 trigger_name,
79 expected_trigger_name);
7d59def2 80 }
65f64978
JG
81end:
82 return names_match;
6ba31891
FD
83}
84
85int main(int argc, char **argv)
86{
87 int ret;
88 int option;
89 int option_index;
3e68c9e8
JG
90 char *expected_trigger_name = NULL;
91 char *end_trigger_name = NULL;
6ba31891
FD
92 struct lttng_triggers *triggers = NULL;
93 unsigned int count, i, subcription_count = 0;
94 enum lttng_trigger_status trigger_status;
95 char *after_notif_register_file_path = NULL;
96 struct lttng_notification_channel *notification_channel = NULL;
6ffce1f5 97 int expected_notifications = 1, notification_count = 0;
6ba31891 98
28f23191 99 while ((option = getopt_long(argc, argv, "a:b:c:t:", long_options, &option_index)) != -1) {
6ba31891
FD
100 switch (option) {
101 case 'a':
102 after_notif_register_file_path = strdup(optarg);
103 break;
6ffce1f5
JR
104 case 'b':
105 expected_notifications = atoi(optarg);
106 break;
107 case 'c':
108 end_trigger_name = strdup(optarg);
109 break;
6ba31891
FD
110 case 't':
111 expected_trigger_name = strdup(optarg);
112 break;
113 case '?':
114 /* getopt_long already printed an error message. */
115 default:
116 ret = -1;
117 goto end;
118 }
119 }
120
121 if (optind != argc) {
122 ret = -1;
123 goto end;
124 }
125
28f23191
JG
126 notification_channel =
127 lttng_notification_channel_create(lttng_session_daemon_notification_endpoint);
6ba31891
FD
128 if (!notification_channel) {
129 fprintf(stderr, "Failed to create notification channel\n");
130 ret = -1;
131 goto end;
132 }
133
134 ret = lttng_list_triggers(&triggers);
135 if (ret != LTTNG_OK) {
136 fprintf(stderr, "Failed to list triggers\n");
7d59def2 137 ret = -1;
6ba31891
FD
138 goto end;
139 }
140
141 trigger_status = lttng_triggers_get_count(triggers, &count);
142 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
143 fprintf(stderr, "Failed to get trigger count\n");
144 ret = -1;
145 goto end;
146 }
147
7d59def2 148 /* Look for the trigger we want to subscribe to. */
6ba31891 149 for (i = 0; i < count; i++) {
28f23191 150 const struct lttng_trigger *trigger = lttng_triggers_get_at_index(triggers, i);
6ba31891 151 const struct lttng_condition *condition =
28f23191
JG
152 lttng_trigger_get_const_condition(trigger);
153 const struct lttng_action *action = lttng_trigger_get_const_action(trigger);
154 const enum lttng_action_type action_type = lttng_action_get_type(action);
6ba31891
FD
155 enum lttng_notification_channel_status channel_status;
156 const char *trigger_name = NULL;
157
158 lttng_trigger_get_name(trigger, &trigger_name);
5c7248cd 159 if (strcmp(trigger_name, expected_trigger_name) != 0) {
6ffce1f5
JR
160 /* Might match the end event trigger */
161 if (end_trigger_name != NULL &&
28f23191 162 strcmp(trigger_name, end_trigger_name) != 0) {
6ffce1f5
JR
163 continue;
164 }
6ba31891 165 }
7c2fae7c 166 if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
28f23191
JG
167 action_list_contains_notify(action)) ||
168 action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
6ba31891
FD
169 /* "The action of trigger is not notify, skipping. */
170 continue;
171 }
172
28f23191
JG
173 channel_status =
174 lttng_notification_channel_subscribe(notification_channel, condition);
6ba31891 175 if (channel_status) {
28f23191
JG
176 fprintf(stderr,
177 "Failed to subscribe to notifications of trigger \"%s\"\n",
178 trigger_name);
6ba31891
FD
179 ret = -1;
180 goto end;
181 }
182
183 subcription_count++;
184 }
185
186 if (subcription_count == 0) {
6ffce1f5
JR
187 fprintf(stderr, "No matching trigger with a notify action found.\n");
188 ret = -1;
6ba31891
FD
189 goto end;
190 }
191
6ffce1f5
JR
192 if (end_trigger_name != NULL && subcription_count != 2) {
193 fprintf(stderr, "No matching end event trigger with a notify action found.\n");
194 ret = -1;
195 goto end;
196 }
6ba31891
FD
197
198 /*
199 * We registered to the notification of our target trigger. We can now
200 * create the sync file to signify that we are ready.
201 */
202 ret = create_file(after_notif_register_file_path);
203 if (ret != 0) {
204 goto end;
205 }
206
207 for (;;) {
208 struct lttng_notification *notification;
209 enum lttng_notification_channel_status channel_status;
210
28f23191
JG
211 channel_status = lttng_notification_channel_get_next_notification(
212 notification_channel, &notification);
6ba31891
FD
213 switch (channel_status) {
214 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
215 printf("Dropped notification\n");
7d59def2
JR
216 ret = -1;
217 goto end;
6ba31891 218 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
7d59def2 219 ret = -1;
6ba31891
FD
220 goto end;
221 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
222 break;
223 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
224 printf("Notification channel was closed by peer.\n");
225 break;
226 default:
28f23191
JG
227 fprintf(stderr,
228 "A communication error occurred on the notification channel.\n");
6ba31891
FD
229 ret = -1;
230 goto end;
231 }
232
6ffce1f5 233 /* Early exit check. */
28f23191 234 if (end_trigger_name != NULL && is_trigger_name(end_trigger_name, notification)) {
6ffce1f5
JR
235 /* Exit the loop immediately. */
236 printf("Received end event notification from trigger %s\n",
28f23191 237 end_trigger_name);
6ffce1f5
JR
238 lttng_notification_destroy(notification);
239 goto evaluate_success;
240 }
241
7d59def2 242 ret = is_trigger_name(expected_trigger_name, notification);
6ba31891 243 lttng_notification_destroy(notification);
7d59def2
JR
244 if (!ret) {
245 ret = -1;
246 goto end;
6ffce1f5
JR
247 }
248
28f23191 249 printf("Received event notification from trigger %s\n", expected_trigger_name);
6ffce1f5 250 notification_count++;
28f23191 251 if (end_trigger_name == NULL && expected_notifications == notification_count) {
6ffce1f5
JR
252 /*
253 * Here the loop exit is controlled by the number of
254 * notification and not by the reception of the end
255 * event trigger notification. This represent the
256 * default behavior.
257 *
258 */
259 goto evaluate_success;
6ba31891
FD
260 }
261 }
6ffce1f5
JR
262
263evaluate_success:
264 if (expected_notifications == notification_count) {
265 /* Success */
266 ret = 0;
267 } else {
28f23191
JG
268 fprintf(stderr,
269 "Expected %d notification got %d\n",
270 expected_notifications,
271 notification_count);
6ffce1f5
JR
272 ret = 1;
273 }
274
6ba31891
FD
275end:
276 lttng_triggers_destroy(triggers);
277 lttng_notification_channel_destroy(notification_channel);
3e68c9e8
JG
278 free(after_notif_register_file_path);
279 free(end_trigger_name);
280 free(expected_trigger_name);
6ba31891
FD
281 return !!ret;
282}
This page took 0.058236 seconds and 4 git commands to generate.