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