688775a6e72b2ab97c4419efac7726fb201281dc
[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/on-event.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, 'i'},
26 {"sync-after-notif-register", required_argument, 0, 'a'},
27 {0, 0, 0, 0}
28 };
29
30 static bool action_group_contains_notify(
31 const struct lttng_action *action_group)
32 {
33 unsigned int i, count;
34 enum lttng_action_status status =
35 lttng_action_group_get_count(action_group, &count);
36
37 if (status != LTTNG_ACTION_STATUS_OK) {
38 printf("Failed to get action count from action group\n");
39 exit(1);
40 }
41
42 for (i = 0; i < count; i++) {
43 const struct lttng_action *action =
44 lttng_action_group_get_at_index(
45 action_group, i);
46 const enum lttng_action_type action_type =
47 lttng_action_get_type(action);
48
49 if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
50 return true;
51 }
52 }
53 return false;
54 }
55
56 static bool is_expected_trigger_name(const char *expected_trigger_name,
57 struct lttng_notification *notification)
58 {
59 const char *trigger_name = NULL;
60 enum lttng_trigger_status trigger_status;
61 const struct lttng_trigger *trigger;
62 bool names_match;
63
64 trigger = lttng_notification_get_trigger(notification);
65 if (!trigger) {
66 fprintf(stderr, "Failed to get trigger from notification\n");
67 names_match = false;
68 goto end;
69 }
70
71 trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
72 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
73 fprintf(stderr, "Failed to get name from notification's trigger\n");
74 names_match = false;
75 goto end;
76 }
77
78 names_match = strcmp(expected_trigger_name, trigger_name) == 0;
79 end:
80 return names_match;
81 }
82
83 int main(int argc, char **argv)
84 {
85 int ret;
86 int option;
87 int option_index;
88 const char *expected_trigger_name = NULL;
89 struct lttng_triggers *triggers = NULL;
90 unsigned int count, i, subcription_count = 0;
91 enum lttng_trigger_status trigger_status;
92 char *after_notif_register_file_path = NULL;
93 struct lttng_notification_channel *notification_channel = NULL;
94
95 while ((option = getopt_long(argc, argv, "a:t:",
96 long_options, &option_index)) != -1) {
97 switch (option) {
98 case 'a':
99 after_notif_register_file_path = strdup(optarg);
100 break;
101 case 't':
102 expected_trigger_name = strdup(optarg);
103 break;
104 case '?':
105 /* getopt_long already printed an error message. */
106 default:
107 ret = -1;
108 goto end;
109 }
110 }
111
112 if (optind != argc) {
113 ret = -1;
114 goto end;
115 }
116
117
118 notification_channel = lttng_notification_channel_create(
119 lttng_session_daemon_notification_endpoint);
120 if (!notification_channel) {
121 fprintf(stderr, "Failed to create notification channel\n");
122 ret = -1;
123 goto end;
124 }
125
126 ret = lttng_list_triggers(&triggers);
127 if (ret != LTTNG_OK) {
128 fprintf(stderr, "Failed to list triggers\n");
129 goto end;
130 }
131
132 trigger_status = lttng_triggers_get_count(triggers, &count);
133 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
134 fprintf(stderr, "Failed to get trigger count\n");
135 ret = -1;
136 goto end;
137 }
138
139 for (i = 0; i < count; i++) {
140 const struct lttng_trigger *trigger =
141 lttng_triggers_get_at_index(triggers, i);
142 const struct lttng_condition *condition =
143 lttng_trigger_get_const_condition(trigger);
144 const struct lttng_action *action =
145 lttng_trigger_get_const_action(trigger);
146 const enum lttng_action_type action_type =
147 lttng_action_get_type(action);
148 enum lttng_notification_channel_status channel_status;
149 const char *trigger_name = NULL;
150
151 lttng_trigger_get_name(trigger, &trigger_name);
152 if (strcmp(trigger_name, expected_trigger_name)) {
153 continue;
154 }
155
156 if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
157 action_group_contains_notify(action)) ||
158 action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
159 /* "The action of trigger is not notify, skipping. */
160 continue;
161 }
162
163 channel_status = lttng_notification_channel_subscribe(
164 notification_channel, condition);
165 if (channel_status) {
166 fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
167 trigger_name);
168 ret = -1;
169 goto end;
170 }
171
172 subcription_count++;
173 }
174
175 if (subcription_count == 0) {
176 printf("No matching trigger with a notify action found.\n");
177 ret = 0;
178 goto end;
179 }
180
181
182 /*
183 * We registered to the notification of our target trigger. We can now
184 * create the sync file to signify that we are ready.
185 */
186 ret = create_file(after_notif_register_file_path);
187 if (ret != 0) {
188 goto end;
189 }
190
191 for (;;) {
192 struct lttng_notification *notification;
193 enum lttng_notification_channel_status channel_status;
194
195 channel_status =
196 lttng_notification_channel_get_next_notification(
197 notification_channel,
198 &notification);
199 switch (channel_status) {
200 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
201 printf("Dropped notification\n");
202 break;
203 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
204 ret = 0;
205 goto end;
206 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
207 break;
208 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
209 printf("Notification channel was closed by peer.\n");
210 break;
211 default:
212 fprintf(stderr, "A communication error occurred on the notification channel.\n");
213 ret = -1;
214 goto end;
215 }
216
217 ret = is_expected_trigger_name(expected_trigger_name,
218 notification);
219 lttng_notification_destroy(notification);
220 if (ret) {
221 ret = 0;
222 goto end;
223 }
224 }
225 end:
226 lttng_triggers_destroy(triggers);
227 lttng_notification_channel_destroy(notification_channel);
228 return !!ret;
229 }
This page took 0.050301 seconds and 3 git commands to generate.