Commit | Line | Data |
---|---|---|
ebdb334b JR |
1 | /* |
2 | * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com> | |
3 | * | |
4 | * SPDX-License-Identifier: LGPL-2.1-only | |
5 | * | |
6 | */ | |
7 | ||
8 | #include <stdlib.h> | |
9 | #include <inttypes.h> | |
10 | ||
11 | #include <common/dynamic-array.h> | |
12 | #include <common/error.h> | |
13 | #include <common/macros.h> | |
14 | #include <common/payload.h> | |
15 | #include <common/payload-view.h> | |
16 | ||
17 | #include <lttng/map-key.h> | |
18 | #include <lttng/map-key-internal.h> | |
19 | ||
20 | #define TOKEN_VAR_EVENT_NAME "EVENT_NAME" | |
21 | #define TOKEN_VAR_PROVIDER_NAME "PROVIDER_NAME" | |
22 | ||
23 | static | |
24 | void destroy_map_key_token(void *ptr) | |
25 | { | |
26 | struct lttng_map_key_token *token = (struct lttng_map_key_token *) ptr; | |
27 | switch (token->type) { | |
28 | case LTTNG_MAP_KEY_TOKEN_TYPE_STRING: | |
29 | { | |
30 | struct lttng_map_key_token_string *token_string = | |
31 | (struct lttng_map_key_token_string *) token; | |
32 | free(token_string->string); | |
33 | break; | |
34 | } | |
35 | case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE: | |
36 | break; | |
37 | default: | |
38 | abort(); | |
39 | } | |
40 | ||
41 | free(token); | |
42 | } | |
43 | ||
44 | struct lttng_map_key *lttng_map_key_create(void) | |
45 | { | |
46 | struct lttng_map_key *key = NULL; | |
47 | ||
48 | key = zmalloc(sizeof(*key)); | |
49 | if (!key) { | |
50 | return NULL; | |
51 | } | |
52 | ||
53 | urcu_ref_init(&key->ref); | |
54 | lttng_dynamic_pointer_array_init(&key->tokens, | |
55 | destroy_map_key_token); | |
56 | ||
57 | return key; | |
58 | } | |
59 | ||
60 | ssize_t lttng_map_key_create_from_payload(struct lttng_payload_view *src_view, | |
61 | struct lttng_map_key **out_key) | |
62 | { | |
63 | ssize_t ret, consumed_len; | |
64 | uint32_t i; | |
65 | const struct lttng_map_key_comm *comm; | |
66 | struct lttng_map_key *key; | |
67 | ||
68 | if (!src_view || !out_key) { | |
69 | ret = -1; | |
70 | goto end; | |
71 | } | |
72 | ||
73 | key = lttng_map_key_create(); | |
74 | if (!key) { | |
75 | ret = -1; | |
76 | goto end; | |
77 | } | |
78 | ||
79 | comm = (typeof(comm)) src_view->buffer.data; | |
80 | consumed_len = sizeof(*comm); | |
81 | ||
82 | assert(comm->token_count > 0); | |
83 | ||
84 | for (i = 0; i < comm->token_count; i++) { | |
85 | enum lttng_map_key_status key_status; | |
86 | const struct lttng_map_key_token_comm *token_comm; | |
87 | struct lttng_payload_view child_view = | |
88 | lttng_payload_view_from_view(src_view, consumed_len, | |
89 | src_view->buffer.size - consumed_len); | |
90 | if (!lttng_payload_view_is_valid(&child_view)) { | |
91 | ret = -1; | |
92 | goto end; | |
93 | } | |
94 | ||
95 | token_comm = (const struct lttng_map_key_token_comm *) child_view.buffer.data; | |
96 | ||
97 | switch (token_comm->type) { | |
98 | case LTTNG_MAP_KEY_TOKEN_TYPE_STRING: | |
99 | { | |
100 | const char *str_val; | |
101 | const struct lttng_map_key_token_string_comm *comm; | |
102 | ||
103 | comm = (typeof(comm)) token_comm; | |
104 | str_val = (const char *) &comm->payload; | |
105 | ||
106 | if (!lttng_buffer_view_contains_string(&child_view.buffer, | |
107 | str_val, comm->string_len)) { | |
108 | ret = -1; | |
109 | goto end; | |
110 | } | |
111 | ||
112 | key_status = lttng_map_key_append_token_string(key, str_val); | |
113 | if (key_status != LTTNG_MAP_KEY_STATUS_OK) { | |
114 | ret = -1; | |
115 | goto end; | |
116 | } | |
117 | ||
118 | consumed_len += sizeof(*comm) + comm->string_len; | |
119 | ||
120 | break; | |
121 | } | |
122 | case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE: | |
123 | { | |
124 | const struct lttng_map_key_token_variable_comm *comm; | |
125 | ||
126 | comm = (typeof(comm)) token_comm; | |
127 | key_status = lttng_map_key_append_token_variable(key, | |
128 | comm->var_type); | |
129 | if (key_status != LTTNG_MAP_KEY_STATUS_OK) { | |
130 | ret = -1; | |
131 | goto end; | |
132 | } | |
133 | ||
134 | consumed_len += sizeof(*comm); | |
135 | break; | |
136 | } | |
137 | default: | |
138 | abort(); | |
139 | } | |
140 | } | |
141 | ||
142 | *out_key = key; | |
143 | ret = consumed_len; | |
144 | end: | |
145 | return ret; | |
146 | } | |
147 | ||
148 | int lttng_map_key_serialize(const struct lttng_map_key *key, | |
149 | struct lttng_payload *payload) | |
150 | { | |
151 | int ret; | |
152 | uint32_t i, nb_tokens; | |
153 | enum lttng_map_key_status key_status; | |
154 | struct lttng_map_key_comm comm = {0}; | |
155 | ||
156 | DBG("Serializing map key"); | |
157 | ||
158 | key_status = lttng_map_key_get_token_count(key, &nb_tokens); | |
159 | if (key_status != LTTNG_MAP_KEY_STATUS_OK) { | |
160 | ret = -1; | |
161 | goto end; | |
162 | } | |
163 | ||
164 | if (nb_tokens == 0) { | |
165 | ERR("Map key token number is zero"); | |
166 | ret = -1; | |
167 | goto end; | |
168 | } | |
169 | ||
170 | DBG("Serializing map key token count: %" PRIu32, nb_tokens); | |
171 | comm.token_count = nb_tokens; | |
172 | ||
173 | ret = lttng_dynamic_buffer_append(&payload->buffer, &comm, | |
174 | sizeof(comm)); | |
175 | if (ret) { | |
176 | goto end; | |
177 | } | |
178 | ||
179 | for (i = 0; i < nb_tokens; i++) { | |
180 | uint8_t token_type; | |
181 | const struct lttng_map_key_token *token = | |
182 | lttng_map_key_get_token_at_index(key, i); | |
183 | DBG("Serializing map key token's type: %d", token->type); | |
184 | ||
185 | token_type = (uint8_t) token->type; | |
186 | ||
187 | switch (token->type) { | |
188 | case LTTNG_MAP_KEY_TOKEN_TYPE_STRING: | |
189 | { | |
190 | struct lttng_map_key_token_string *str_token = | |
191 | (struct lttng_map_key_token_string *) token; | |
192 | struct lttng_map_key_token_string_comm comm = {0}; | |
193 | uint32_t len = strlen(str_token->string) + 1; | |
194 | ||
195 | DBG("Serializing a string type key token"); | |
196 | comm.parent_type = token_type; | |
197 | comm.string_len = len; | |
198 | ||
199 | /* Serialize the length, include the null character */ | |
200 | DBG("Serializing map key token string length (include null character):" | |
201 | "%" PRIu32, len); | |
202 | ret = lttng_dynamic_buffer_append(&payload->buffer, | |
203 | &comm, sizeof(comm)); | |
204 | if (ret) { | |
205 | goto end; | |
206 | } | |
207 | ||
208 | /* Serialize the string */ | |
209 | DBG("Serializing map key token string's value: \"%s\"", | |
210 | str_token->string); | |
211 | ret = lttng_dynamic_buffer_append(&payload->buffer, | |
212 | str_token->string, len); | |
213 | if (ret) { | |
214 | goto end; | |
215 | } | |
216 | ||
217 | break; | |
218 | } | |
219 | case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE: | |
220 | { | |
221 | struct lttng_map_key_token_variable *var_token = | |
222 | (struct lttng_map_key_token_variable *) token; | |
223 | struct lttng_map_key_token_variable_comm comm = {0}; | |
224 | ||
225 | DBG("Serializing a variable type key token"); | |
226 | ||
227 | comm.parent_type = token_type; | |
228 | comm.var_type = var_token->type; | |
229 | ||
230 | ret = lttng_dynamic_buffer_append(&payload->buffer, | |
231 | &comm, sizeof(comm)); | |
232 | if (ret) { | |
233 | goto end; | |
234 | } | |
235 | ||
236 | break; | |
237 | } | |
238 | default: | |
239 | abort(); | |
240 | } | |
241 | } | |
242 | ||
243 | end: | |
244 | return ret; | |
245 | } | |
246 | ||
247 | static inline | |
248 | bool token_variable_type_is_valid(enum lttng_map_key_token_variable_type var_type) | |
249 | { | |
250 | switch (var_type) { | |
251 | case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME: | |
252 | case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME: | |
253 | return true; | |
254 | default: | |
255 | return false; | |
256 | } | |
257 | } | |
258 | ||
259 | static bool lttng_map_key_token_variable_is_equal( | |
260 | const struct lttng_map_key_token *_a, | |
261 | const struct lttng_map_key_token *_b) | |
262 | { | |
263 | struct lttng_map_key_token_variable *a, *b; | |
264 | assert(_a->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE); | |
265 | assert(_b->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE); | |
266 | ||
267 | a = container_of(_a, struct lttng_map_key_token_variable, parent); | |
268 | b = container_of(_b, struct lttng_map_key_token_variable, parent); | |
269 | ||
270 | return lttng_map_key_token_variable_get_type(a) == | |
271 | lttng_map_key_token_variable_get_type(b); | |
272 | } | |
273 | ||
274 | enum lttng_map_key_status lttng_map_key_append_token_variable( | |
275 | struct lttng_map_key *key, | |
276 | enum lttng_map_key_token_variable_type var_type) | |
277 | { | |
278 | int ret; | |
279 | enum lttng_map_key_status status; | |
280 | struct lttng_map_key_token_variable *token = NULL; | |
281 | ||
282 | if (!token_variable_type_is_valid(var_type)) { | |
283 | ERR("Invalid token variable type"); | |
284 | status = LTTNG_MAP_KEY_STATUS_INVALID; | |
285 | goto end; | |
286 | } | |
287 | ||
288 | token = zmalloc(sizeof(*token)); | |
289 | if (!token) { | |
290 | status = LTTNG_MAP_KEY_STATUS_ERROR; | |
291 | goto end; | |
292 | } | |
293 | ||
294 | token->parent.type = LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE; | |
295 | token->parent.equal = lttng_map_key_token_variable_is_equal; | |
296 | token->type = var_type; | |
297 | ||
298 | ret = lttng_dynamic_pointer_array_add_pointer( | |
299 | &key->tokens, token); | |
300 | if (ret) { | |
301 | status = LTTNG_MAP_KEY_STATUS_ERROR; | |
302 | goto end; | |
303 | } | |
304 | ||
305 | status = LTTNG_MAP_KEY_STATUS_OK; | |
306 | ||
307 | end: | |
308 | return status; | |
309 | } | |
310 | ||
311 | static bool lttng_map_key_token_string_is_equal( | |
312 | const struct lttng_map_key_token *_a, | |
313 | const struct lttng_map_key_token *_b) | |
314 | { | |
315 | struct lttng_map_key_token_string *a, *b; | |
316 | const char *a_string, *b_string; | |
317 | ||
318 | assert(_a->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING); | |
319 | assert(_b->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING); | |
320 | ||
321 | a = container_of(_a, struct lttng_map_key_token_string, parent); | |
322 | b = container_of(_b, struct lttng_map_key_token_string, parent); | |
323 | ||
324 | a_string = lttng_map_key_token_string_get_string(a); | |
325 | b_string = lttng_map_key_token_string_get_string(b); | |
326 | ||
327 | return !strcmp(a_string, b_string); | |
328 | } | |
329 | ||
330 | enum lttng_map_key_status lttng_map_key_append_token_string( | |
331 | struct lttng_map_key *key, const char *string) | |
332 | { | |
333 | int ret; | |
334 | enum lttng_map_key_status status; | |
335 | struct lttng_map_key_token_string *token = NULL; | |
336 | ||
337 | ||
338 | token = zmalloc(sizeof(*token)); | |
339 | if (!token) { | |
340 | status = LTTNG_MAP_KEY_STATUS_ERROR; | |
341 | goto end; | |
342 | } | |
343 | ||
344 | token->parent.type = LTTNG_MAP_KEY_TOKEN_TYPE_STRING; | |
345 | token->parent.equal = lttng_map_key_token_string_is_equal; | |
346 | token->string = strdup(string); | |
347 | if (!token->string) { | |
348 | status = LTTNG_MAP_KEY_STATUS_ERROR; | |
349 | goto end; | |
350 | } | |
351 | ||
352 | ret = lttng_dynamic_pointer_array_add_pointer( | |
353 | &key->tokens, token); | |
354 | if (ret) { | |
355 | status = LTTNG_MAP_KEY_STATUS_ERROR; | |
356 | goto end; | |
357 | } | |
358 | ||
359 | status = LTTNG_MAP_KEY_STATUS_OK; | |
360 | end: | |
361 | return status; | |
362 | } | |
363 | ||
364 | enum lttng_map_key_status lttng_map_key_get_token_count( | |
365 | const struct lttng_map_key *key, unsigned int *count) | |
366 | { | |
367 | enum lttng_map_key_status status; | |
368 | if (!key || !count) { | |
369 | status = LTTNG_MAP_KEY_STATUS_INVALID; | |
370 | goto end; | |
371 | ||
372 | } | |
373 | ||
374 | *count = lttng_dynamic_pointer_array_get_count( | |
375 | &key->tokens); | |
376 | ||
377 | status = LTTNG_MAP_KEY_STATUS_OK; | |
378 | end: | |
379 | return status; | |
380 | } | |
381 | ||
382 | const struct lttng_map_key_token * | |
383 | lttng_map_key_get_token_at_index(const struct lttng_map_key *key, | |
384 | unsigned int index) | |
385 | { | |
386 | const struct lttng_map_key_token *token = NULL; | |
387 | enum lttng_map_key_status status; | |
388 | unsigned int count; | |
389 | ||
390 | if (!key) { | |
391 | goto end; | |
392 | } | |
393 | ||
394 | status = lttng_map_key_get_token_count(key, &count); | |
395 | if (status != LTTNG_MAP_KEY_STATUS_OK) { | |
396 | goto end; | |
397 | } | |
398 | ||
399 | if (index >= count) { | |
400 | goto end; | |
401 | } | |
402 | ||
403 | token = lttng_dynamic_pointer_array_get_pointer(&key->tokens, | |
404 | index); | |
405 | ||
406 | end: | |
407 | return token; | |
408 | } | |
409 | ||
410 | enum lttng_map_key_token_variable_type lttng_map_key_token_variable_get_type( | |
411 | const struct lttng_map_key_token_variable *token) | |
412 | { | |
413 | assert(token->parent.type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE); | |
414 | ||
415 | return token->type; | |
416 | } | |
417 | ||
418 | const char *lttng_map_key_token_string_get_string( | |
419 | const struct lttng_map_key_token_string *token) | |
420 | { | |
421 | assert(token->parent.type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING); | |
422 | ||
423 | return token->string; | |
424 | } | |
425 | ||
426 | void lttng_map_key_destroy(struct lttng_map_key *key) | |
427 | { | |
428 | lttng_map_key_put(key); | |
429 | } | |
430 | ||
431 | LTTNG_HIDDEN | |
432 | struct lttng_map_key *lttng_map_key_parse_from_string(const char *_key_str) | |
433 | { | |
434 | struct lttng_map_key *key = NULL; | |
435 | enum lttng_map_key_status status; | |
436 | char *key_str = NULL, *curr_pos; | |
437 | ||
438 | key = lttng_map_key_create(); | |
439 | if (!key) { | |
440 | goto end; | |
441 | } | |
442 | ||
443 | key_str = strdup(_key_str); | |
444 | ||
445 | curr_pos = key_str; | |
446 | ||
447 | curr_pos = strtok(curr_pos, "$}"); | |
448 | while (curr_pos) { | |
449 | if (curr_pos[0] == '{') { | |
450 | if (strncmp(&curr_pos[1], TOKEN_VAR_EVENT_NAME, strlen(TOKEN_VAR_EVENT_NAME)) == 0) { | |
451 | status = lttng_map_key_append_token_variable(key, | |
452 | LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME); | |
453 | if (status != LTTNG_MAP_KEY_STATUS_OK) { | |
454 | goto error; | |
455 | } | |
456 | } else if (strncmp(&curr_pos[1], TOKEN_VAR_PROVIDER_NAME, strlen(TOKEN_VAR_PROVIDER_NAME)) == 0) { | |
457 | status = lttng_map_key_append_token_variable(key, | |
458 | LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME); | |
459 | if (status != LTTNG_MAP_KEY_STATUS_OK) { | |
460 | goto error; | |
461 | } | |
462 | } else { | |
463 | goto error; | |
464 | } | |
465 | } else { | |
466 | status = lttng_map_key_append_token_string(key, curr_pos); | |
467 | if (status != LTTNG_MAP_KEY_STATUS_OK) { | |
468 | goto error; | |
469 | } | |
470 | } | |
471 | curr_pos = strtok(NULL, "$}"); | |
472 | } | |
473 | goto end; | |
474 | ||
475 | error: | |
476 | lttng_map_key_destroy(key); | |
477 | key = NULL; | |
478 | end: | |
479 | free(key_str); | |
480 | ||
481 | return key; | |
482 | } | |
483 | ||
484 | LTTNG_HIDDEN | |
485 | bool lttng_map_key_is_equal( | |
486 | const struct lttng_map_key *a, const struct lttng_map_key *b) | |
487 | { | |
488 | bool is_equal = false; | |
489 | enum lttng_map_key_status status; | |
490 | unsigned int a_count, b_count, i; | |
491 | ||
492 | if (!!a != !!b) { | |
493 | goto end; | |
494 | } | |
495 | ||
496 | if (a == NULL && b == NULL) { | |
497 | is_equal = true; | |
498 | goto end; | |
499 | } | |
500 | ||
501 | if (a == b) { | |
502 | is_equal = true; | |
503 | goto end; | |
504 | } | |
505 | ||
506 | status = lttng_map_key_get_token_count(a, &a_count); | |
507 | assert(status == LTTNG_MAP_KEY_STATUS_OK); | |
508 | status = lttng_map_key_get_token_count(b, &b_count); | |
509 | assert(status == LTTNG_MAP_KEY_STATUS_OK); | |
510 | ||
511 | if (a_count != b_count) { | |
512 | goto end; | |
513 | } | |
514 | ||
515 | for (i = 0; i < a_count; i++) { | |
516 | const struct lttng_map_key_token *token_a = NULL, *token_b = NULL; | |
517 | ||
518 | token_a = lttng_map_key_get_token_at_index(a, i); | |
519 | token_b = lttng_map_key_get_token_at_index(b, i); | |
520 | ||
521 | /* JORAJ TODO: is order important for the map key token? */ | |
522 | if(token_a->type != token_b->type) { | |
523 | goto end; | |
524 | } | |
525 | ||
526 | if(!token_a->equal(token_a, token_b)) { | |
527 | goto end; | |
528 | } | |
529 | } | |
530 | ||
531 | is_equal = true; | |
532 | ||
533 | end: | |
534 | return is_equal; | |
535 | ||
536 | ||
537 | } | |
538 | ||
539 | static void map_key_destroy_ref(struct urcu_ref *ref) | |
540 | { | |
541 | struct lttng_map_key *key = container_of(ref, struct lttng_map_key, ref); | |
542 | ||
543 | lttng_dynamic_pointer_array_reset(&key->tokens); | |
544 | free(key); | |
545 | } | |
546 | ||
547 | LTTNG_HIDDEN | |
548 | void lttng_map_key_get(struct lttng_map_key *key) | |
549 | { | |
550 | urcu_ref_get(&key->ref); | |
551 | } | |
552 | ||
553 | LTTNG_HIDDEN | |
554 | void lttng_map_key_put(struct lttng_map_key *key) | |
555 | { | |
556 | if (!key) { | |
557 | return; | |
558 | } | |
559 | ||
560 | urcu_ref_put(&key->ref, map_key_destroy_ref); | |
561 | } |