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