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