Fix: sessiond: notification: use after free of trigger object
[lttng-tools.git] / tests / regression / tools / notification / base_client.c
1 /*
2 * base_client.c
3 *
4 * Base client application for testing of LTTng notification API
5 *
6 * Copyright 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
7 *
8 * SPDX-License-Identifier: MIT
9 *
10 */
11
12 #include <stdio.h>
13 #include <stdbool.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <inttypes.h>
17 #include <assert.h>
18
19 #include <lttng/action/action.h>
20 #include <lttng/action/group.h>
21 #include <lttng/action/notify.h>
22 #include <lttng/condition/buffer-usage.h>
23 #include <lttng/condition/condition.h>
24 #include <lttng/condition/evaluation.h>
25 #include <lttng/domain.h>
26 #include <lttng/endpoint.h>
27 #include <lttng/notification/channel.h>
28 #include <lttng/notification/notification.h>
29 #include <lttng/trigger/trigger.h>
30 #include <lttng/lttng-error.h>
31
32 static unsigned int nr_notifications = 0;
33 static unsigned int nr_expected_notifications = 0;
34 static const char *session_name = NULL;
35 static const char *channel_name = NULL;
36 static double threshold_ratio = 0.0;
37 static uint64_t threshold_bytes = 0;
38 static bool is_threshold_ratio = false;
39 static bool use_action_group = false;
40 static enum lttng_condition_type buffer_usage_type = LTTNG_CONDITION_TYPE_UNKNOWN;
41 static enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
42
43 int handle_condition(
44 const struct lttng_condition *condition,
45 const struct lttng_evaluation *condition_evaluation);
46
47 static
48 int parse_arguments(char **argv)
49 {
50 const char *domain_type_string = NULL;
51 const char *buffer_usage_type_string = NULL;
52 const char *buffer_usage_threshold_type = NULL;
53 const char *buffer_usage_threshold_value = NULL;
54 const char *nr_expected_notifications_string = NULL;
55 const char *use_action_group_value = NULL;
56
57 session_name = argv[1];
58 channel_name = argv[2];
59 domain_type_string = argv[3];
60 buffer_usage_type_string = argv[4];
61 buffer_usage_threshold_type = argv[5];
62 buffer_usage_threshold_value = argv[6];
63 nr_expected_notifications_string = argv[7];
64 use_action_group_value = argv[8];
65
66 /* Parse arguments */
67 /* Domain type */
68 if (!strcasecmp("LTTNG_DOMAIN_UST", domain_type_string)) {
69 domain_type = LTTNG_DOMAIN_UST;
70 }
71 if (!strcasecmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
72 domain_type = LTTNG_DOMAIN_KERNEL;
73 }
74 if (domain_type == LTTNG_DOMAIN_NONE) {
75 printf("error: Unknown domain type\n");
76 goto error;
77 }
78
79 /* Buffer usage condition type */
80 if (!strcasecmp("low", buffer_usage_type_string)) {
81 buffer_usage_type = LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW;
82 }
83 if (!strcasecmp("high", buffer_usage_type_string)) {
84 buffer_usage_type = LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH;
85 }
86 if (buffer_usage_type == LTTNG_CONDITION_TYPE_UNKNOWN) {
87 printf("error: Unknown condition type\n");
88 goto error;
89 }
90
91 /* Ratio or bytes ? */
92 if (!strcasecmp("bytes", buffer_usage_threshold_type)) {
93 is_threshold_ratio = false;
94 sscanf(buffer_usage_threshold_value, "%" SCNu64, &threshold_bytes);
95 }
96
97 if (!strcasecmp("ratio", buffer_usage_threshold_type)) {
98 is_threshold_ratio = true;
99 sscanf(buffer_usage_threshold_value, "%lf", &threshold_ratio);
100 }
101
102 /* Number of notification to expect */
103 sscanf(nr_expected_notifications_string, "%d", &nr_expected_notifications);
104
105 /* Put notify action in a group. */
106 if (!strcasecmp("1", use_action_group_value)) {
107 use_action_group = true;
108 }
109
110 return 0;
111 error:
112 return 1;
113 }
114
115 int main(int argc, char **argv)
116 {
117 int ret = 0;
118 enum lttng_condition_status condition_status;
119 enum lttng_action_status action_status;
120 enum lttng_notification_channel_status nc_status;
121 struct lttng_notification_channel *notification_channel = NULL;
122 struct lttng_condition *condition = NULL;
123 struct lttng_action *action = NULL;
124 struct lttng_trigger *trigger = NULL;
125
126 /*
127 * Disable buffering on stdout.
128 * Safety measure to prevent hang on the validation side since
129 * stdout is used for outside synchronization.
130 */
131 setbuf(stdout, NULL);
132
133 if (argc < 9) {
134 printf("error: Missing arguments for tests\n");
135 ret = 1;
136 goto end;
137 }
138
139 ret = parse_arguments(argv);
140 if (ret) {
141 printf("error: Could not parse arguments\n");
142 goto end;
143 }
144
145 /* Setup */
146 notification_channel = lttng_notification_channel_create(
147 lttng_session_daemon_notification_endpoint);
148 if (!notification_channel) {
149 printf("error: Could not create notification channel\n");
150 ret = 1;
151 goto end;
152 }
153
154 switch (buffer_usage_type) {
155 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
156 condition = lttng_condition_buffer_usage_low_create();
157 break;
158 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
159 condition = lttng_condition_buffer_usage_high_create();
160 break;
161 default:
162 printf("error: Invalid buffer_usage_type\n");
163 ret = 1;
164 goto end;
165 }
166
167 if (!condition) {
168 printf("error: Could not create condition object\n");
169 ret = 1;
170 goto end;
171 }
172
173 if (is_threshold_ratio) {
174 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
175 condition, threshold_ratio);
176 } else {
177 condition_status = lttng_condition_buffer_usage_set_threshold(
178 condition, threshold_bytes);
179 }
180
181 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
182 printf("error: Could not set threshold\n");
183 ret = 1;
184 goto end;
185 }
186
187 condition_status = lttng_condition_buffer_usage_set_session_name(
188 condition, session_name);
189 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
190 printf("error: Could not set session name\n");
191 ret = 1;
192 goto end;
193 }
194 condition_status = lttng_condition_buffer_usage_set_channel_name(
195 condition, channel_name);
196 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
197 printf("error: Could not set channel name\n");
198 ret = 1;
199 goto end;
200 }
201 condition_status = lttng_condition_buffer_usage_set_domain_type(
202 condition, domain_type);
203 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
204 printf("error: Could not set domain type\n");
205 ret = 1;
206 goto end;
207 }
208
209 if (use_action_group) {
210 struct lttng_action *notify, *group;
211
212 group = lttng_action_group_create();
213 if (!group) {
214 printf("error: Could not create action group\n");
215 ret = 1;
216 goto end;
217 }
218
219 notify = lttng_action_notify_create();
220 if (!notify) {
221 lttng_action_destroy(group);
222 printf("error: Could not create action notify\n");
223 ret = 1;
224 goto end;
225 }
226
227 action_status = lttng_action_group_add_action(group, notify);
228 if (action_status != LTTNG_ACTION_STATUS_OK) {
229 printf("error: Could not add action notify to action group\n");
230 lttng_action_destroy(group);
231 lttng_action_destroy(notify);
232 ret = 1;
233 goto end;
234 }
235
236 action = group;
237 } else {
238 action = lttng_action_notify_create();
239 if (!action) {
240 printf("error: Could not create action notify\n");
241 ret = 1;
242 goto end;
243 }
244 }
245
246 trigger = lttng_trigger_create(condition, action);
247 if (!trigger) {
248 printf("error: Could not create trigger\n");
249 ret = 1;
250 goto end;
251 }
252
253 ret = lttng_register_trigger(trigger);
254
255 /*
256 * An equivalent trigger might already be registered if an other app
257 * registered an equivalent trigger.
258 */
259 if (ret < 0 && ret != -LTTNG_ERR_TRIGGER_EXISTS) {
260 printf("error: %s\n", lttng_strerror(ret));
261 ret = 1;
262 goto end;
263 }
264
265 nc_status = lttng_notification_channel_subscribe(notification_channel, condition);
266 if (nc_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
267 printf("error: Could not subscribe\n");
268 ret = 1;
269 goto end;
270 }
271
272 /* Tell outside process that the client is ready */
273 printf("sync: ready\n");
274
275 for (;;) {
276 struct lttng_notification *notification;
277 enum lttng_notification_channel_status status;
278 const struct lttng_evaluation *notification_evaluation;
279 const struct lttng_condition *notification_condition;
280
281 if (nr_notifications == nr_expected_notifications) {
282 ret = 0;
283 goto end;
284 }
285 /* Receive the next notification. */
286 status = lttng_notification_channel_get_next_notification(
287 notification_channel,
288 &notification);
289
290 switch (status) {
291 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
292 break;
293 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
294 ret = 1;
295 printf("error: No drop should be observed during this test app\n");
296 goto end;
297 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
298 /*
299 * The notification channel has been closed by the
300 * session daemon. This is typically caused by a session
301 * daemon shutting down (cleanly or because of a crash).
302 */
303 printf("error: Notification channel was closed\n");
304 ret = 1;
305 goto end;
306 default:
307 /* Unhandled conditions / errors. */
308 printf("error: Unknown notification channel status (%d) \n", status);
309 ret = 1;
310 goto end;
311 }
312
313 notification_condition = lttng_notification_get_condition(notification);
314 notification_evaluation = lttng_notification_get_evaluation(notification);
315
316 ret = handle_condition(notification_condition, notification_evaluation);
317 nr_notifications++;
318
319 lttng_notification_destroy(notification);
320 if (ret != 0) {
321 goto end;
322 }
323 }
324 end:
325 if (trigger) {
326 lttng_unregister_trigger(trigger);
327 }
328 if (lttng_notification_channel_unsubscribe(notification_channel, condition)) {
329 printf("error: channel unsubscribe error\n");
330 }
331 lttng_trigger_destroy(trigger);
332 lttng_condition_destroy(condition);
333 lttng_action_destroy(action);
334 lttng_notification_channel_destroy(notification_channel);
335 printf("exit: %d\n", ret);
336 return ret;
337 }
338
339 int handle_condition(
340 const struct lttng_condition *condition,
341 const struct lttng_evaluation *evaluation)
342 {
343 int ret = 0;
344 const char *string_low = "low";
345 const char *string_high = "high";
346 const char *string_condition_type = NULL;
347 const char *condition_session_name = NULL;
348 const char *condition_channel_name = NULL;
349 enum lttng_condition_type condition_type;
350 enum lttng_domain_type condition_domain_type;
351 double buffer_usage_ratio;
352 uint64_t buffer_usage_bytes;
353
354 condition_type = lttng_condition_get_type(condition);
355
356 if (condition_type != buffer_usage_type) {
357 ret = 1;
358 printf("error: condition type and buffer usage type are not the same\n");
359 goto end;
360 }
361
362 /* Fetch info to test */
363 ret = lttng_condition_buffer_usage_get_session_name(condition,
364 &condition_session_name);
365 if (ret) {
366 printf("error: session name could not be fetched\n");
367 ret = 1;
368 goto end;
369 }
370 ret = lttng_condition_buffer_usage_get_channel_name(condition,
371 &condition_channel_name);
372 if (ret) {
373 printf("error: channel name could not be fetched\n");
374 ret = 1;
375 goto end;
376 }
377 ret = lttng_condition_buffer_usage_get_domain_type(condition,
378 &condition_domain_type);
379 if (ret) {
380 printf("error: domain type could not be fetched\n");
381 ret = 1;
382 goto end;
383 }
384
385 if (strcmp(condition_session_name, session_name) != 0) {
386 printf("error: session name differs\n");
387 ret = 1;
388 goto end;
389 }
390
391 if (strcmp(condition_channel_name, channel_name) != 0) {
392 printf("error: channel name differs\n");
393 ret = 1;
394 goto end;
395 }
396
397 if (condition_domain_type != domain_type) {
398 printf("error: domain type differs\n");
399 ret = 1;
400 goto end;
401 }
402
403 if (is_threshold_ratio) {
404 lttng_evaluation_buffer_usage_get_usage_ratio(
405 evaluation, &buffer_usage_ratio);
406 switch (condition_type) {
407 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
408 if (buffer_usage_ratio > threshold_ratio) {
409 printf("error: buffer usage ratio is bigger than set threshold ratio\n");
410 ret = 1;
411 goto end;
412 }
413 break;
414 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
415 if (buffer_usage_ratio < threshold_ratio) {
416 printf("error: buffer usage ratio is lower than set threshold ratio\n");
417 ret = 1;
418 goto end;
419 }
420 break;
421 default:
422 printf("error: Unknown condition type\n");
423 ret = 1;
424 goto end;
425 }
426 } else {
427 lttng_evaluation_buffer_usage_get_usage(
428 evaluation, &buffer_usage_bytes);
429 switch (condition_type) {
430 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
431 if (buffer_usage_bytes > threshold_bytes) {
432 printf("error: buffer usage ratio is bigger than set threshold bytes\n");
433 ret = 1;
434 goto end;
435 }
436 break;
437 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
438 if (buffer_usage_bytes < threshold_bytes) {
439 printf("error: buffer usage ratio is lower than set threshold bytes\n");
440 ret = 1;
441 goto end;
442 }
443 break;
444 default:
445 printf("error: Unknown condition type\n");
446 ret = 1;
447 goto end;
448 }
449 }
450
451 switch (condition_type) {
452 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
453 string_condition_type = string_low;
454 break;
455 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
456 string_condition_type = string_high;
457 break;
458 default:
459 printf("error: Unknown condition type\n");
460 ret = 1;
461 goto end;
462 }
463
464 printf("notification: %s %d\n", string_condition_type, nr_notifications);
465 end:
466 return ret;
467 }
This page took 0.039073 seconds and 5 git commands to generate.