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