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