1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /* CMetrics
4 * ========
5 * Copyright 2021 Eduardo Silva <eduardo@calyptia.com>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #include <cmetrics/cmetrics.h>
21 #include <cmetrics/cmt_metric.h>
22 #include <cmetrics/cmt_map.h>
23 #include <cmetrics/cmt_sds.h>
24 #include <cmetrics/cmt_counter.h>
25 #include <cmetrics/cmt_gauge.h>
26 #include <cmetrics/cmt_untyped.h>
27 #include <cmetrics/cmt_compat.h>
28 #include <cmetrics/cmt_encode_msgpack.h>
29 #include <cmetrics/cmt_decode_msgpack.h>
30 #include <cmetrics/cmt_mpack_utils.h>
31
find_label_by_index(struct mk_list * label_list,size_t desired_index)32 static struct cmt_map_label *find_label_by_index(struct mk_list *label_list, size_t desired_index)
33 {
34 struct mk_list *head;
35 size_t entry_index;
36
37 entry_index = 0;
38
39 mk_list_foreach(head, label_list) {
40 if (entry_index == desired_index) {
41 return mk_list_entry(head, struct cmt_map_label, _head);
42 }
43
44 entry_index++;
45 }
46
47 return NULL;
48 }
49
unpack_opts_ns(mpack_reader_t * reader,size_t index,void * context)50 static int unpack_opts_ns(mpack_reader_t *reader, size_t index, void *context)
51 {
52 struct cmt_opts *opts;
53
54 opts = (struct cmt_opts *) context;
55
56 return cmt_mpack_consume_string_tag(reader, &opts->ns);
57 }
58
unpack_opts_ss(mpack_reader_t * reader,size_t index,void * context)59 static int unpack_opts_ss(mpack_reader_t *reader, size_t index, void *context)
60 {
61 struct cmt_opts *opts;
62
63 opts = (struct cmt_opts *) context;
64
65 return cmt_mpack_consume_string_tag(reader, &opts->subsystem);
66 }
67
unpack_opts_name(mpack_reader_t * reader,size_t index,void * context)68 static int unpack_opts_name(mpack_reader_t *reader, size_t index, void *context)
69 {
70 struct cmt_opts *opts;
71
72 opts = (struct cmt_opts *) context;
73
74 return cmt_mpack_consume_string_tag(reader, &opts->name);
75 }
76
unpack_opts_desc(mpack_reader_t * reader,size_t index,void * context)77 static int unpack_opts_desc(mpack_reader_t *reader, size_t index, void *context)
78 {
79 struct cmt_opts *opts;
80
81 opts = (struct cmt_opts *) context;
82
83 return cmt_mpack_consume_string_tag(reader, &opts->description);
84 }
85
unpack_opts(mpack_reader_t * reader,struct cmt_opts * opts)86 static int unpack_opts(mpack_reader_t *reader, struct cmt_opts *opts)
87 {
88 int result;
89 struct cmt_mpack_map_entry_callback_t callbacks[] = {
90 {"ns", unpack_opts_ns},
91 {"ss", unpack_opts_ss},
92 {"name", unpack_opts_name},
93 {"desc", unpack_opts_desc},
94 {NULL, NULL}
95 };
96
97 if (NULL == reader ||
98 NULL == opts ) {
99 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
100 }
101
102 memset(opts, 0, sizeof(struct cmt_opts));
103
104 result = cmt_mpack_unpack_map(reader, callbacks, (void *) opts);
105
106 if (CMT_DECODE_MSGPACK_SUCCESS == result) {
107 /* Allocate enough space for the three components, the separators
108 * and the terminator so we don't have to worry about possible realloc issues
109 * later on.
110 */
111
112 opts->fqname = cmt_sds_create_size(cmt_sds_len(opts->ns) + \
113 cmt_sds_len(opts->subsystem) + \
114 cmt_sds_len(opts->name) + \
115 4);
116
117 if (NULL == opts->fqname) {
118 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
119 }
120
121 cmt_sds_cat(opts->fqname, opts->ns, cmt_sds_len(opts->ns));
122 cmt_sds_cat(opts->fqname, "_", 1);
123
124 if (cmt_sds_len(opts->subsystem) > 0) {
125 cmt_sds_cat(opts->fqname, opts->subsystem, cmt_sds_len(opts->subsystem));
126 cmt_sds_cat(opts->fqname, "_", 1);
127 }
128 cmt_sds_cat(opts->fqname, opts->name, cmt_sds_len(opts->name));
129 }
130
131 return result;
132 }
133
unpack_label_dictionary_entry(mpack_reader_t * reader,size_t index,void * context)134 static int unpack_label_dictionary_entry(mpack_reader_t *reader,
135 size_t index,
136 void *context)
137 {
138 int result;
139 struct cmt_map_label *new_label;
140 cmt_sds_t label_name;
141 struct mk_list *target_label_list;
142
143 if (NULL == reader ||
144 NULL == context ) {
145 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
146 }
147
148 target_label_list = (struct mk_list *) context;
149
150 result = cmt_mpack_consume_string_tag(reader, &label_name);
151
152 if (CMT_DECODE_MSGPACK_SUCCESS != result) {
153 cmt_sds_destroy(label_name);
154 return result;
155 }
156
157 new_label = calloc(1, sizeof(struct cmt_map_label));
158
159 if (NULL == new_label) {
160 cmt_sds_destroy(label_name);
161
162 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
163 }
164 else
165 {
166 new_label->name = label_name;
167
168 mk_list_add(&new_label->_head, target_label_list);
169 }
170
171 return CMT_DECODE_MSGPACK_SUCCESS;
172 }
173
unpack_label(mpack_reader_t * reader,size_t index,struct mk_list * unique_label_list,struct mk_list * target_label_list)174 static int unpack_label(mpack_reader_t *reader,
175 size_t index,
176 struct mk_list *unique_label_list,
177 struct mk_list *target_label_list)
178 {
179 int result;
180 struct cmt_map_label *new_label;
181 uint64_t label_index;
182 struct cmt_map_label *dictionary_entry;
183
184 if (NULL == reader ||
185 NULL == unique_label_list ||
186 NULL == target_label_list ) {
187 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
188 }
189
190 result = cmt_mpack_consume_uint_tag(reader, &label_index);
191
192 if (CMT_DECODE_MSGPACK_SUCCESS != result) {
193 return result;
194 }
195
196 dictionary_entry = find_label_by_index(unique_label_list, label_index);
197
198 if (NULL == dictionary_entry) {
199 return CMT_DECODE_MSGPACK_DICTIONARY_LOOKUP_ERROR;
200 }
201
202 new_label = calloc(1, sizeof(struct cmt_map_label));
203
204 if (NULL == new_label) {
205 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
206 }
207 else {
208 new_label->name = cmt_sds_create(dictionary_entry->name);
209
210 if (NULL == new_label->name) {
211 free(new_label);
212
213 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
214 }
215
216 mk_list_add(&new_label->_head, target_label_list);
217 }
218
219 return CMT_DECODE_MSGPACK_SUCCESS;
220 }
221
unpack_static_label(mpack_reader_t * reader,size_t index,void * context)222 static int unpack_static_label(mpack_reader_t *reader, size_t index, void *context)
223 {
224 struct mk_list *target_label_list;
225 struct mk_list *unique_label_list;
226 struct cmt_label *last_static_label;
227 struct cmt_map_label *dictionary_entry;
228 struct cmt_label *new_static_label;
229 struct cmt_msgpack_decode_context *decode_context;
230 uint64_t label_index;
231 int result;
232
233 decode_context = (struct cmt_msgpack_decode_context *) context;
234
235 if (NULL == decode_context) {
236 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
237 }
238
239 unique_label_list = &decode_context->unique_label_list;
240 target_label_list = &decode_context->cmt->static_labels->list;
241
242 if (NULL == reader ||
243 NULL == unique_label_list ||
244 NULL == target_label_list) {
245 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
246 }
247
248 result = cmt_mpack_consume_uint_tag(reader, &label_index);
249
250 if (CMT_DECODE_MSGPACK_SUCCESS != result) {
251 return result;
252 }
253
254 if (decode_context->static_labels_unpacked) {
255 return CMT_DECODE_MSGPACK_SUCCESS;
256 }
257
258 dictionary_entry = find_label_by_index(unique_label_list, label_index);
259
260 if (NULL == dictionary_entry) {
261 return CMT_DECODE_MSGPACK_DICTIONARY_LOOKUP_ERROR;
262 }
263
264 if (0 == (index % 2)) {
265 new_static_label = calloc(1, sizeof(struct cmt_label));
266
267 if (NULL == new_static_label) {
268 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
269 }
270 else {
271 new_static_label->key = cmt_sds_create(dictionary_entry->name);
272
273 if (NULL == new_static_label->key) {
274 free(new_static_label);
275
276 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
277 }
278
279 new_static_label->val = NULL;
280
281 mk_list_add(&new_static_label->_head, target_label_list);
282 }
283 }
284 else {
285 last_static_label = mk_list_entry_last(target_label_list, struct cmt_label, _head);
286
287 if (NULL == last_static_label) {
288 return CMT_DECODE_MSGPACK_DICTIONARY_LOOKUP_ERROR; /* Not quite */
289 }
290
291 last_static_label->val = cmt_sds_create(dictionary_entry->name);
292
293 if (NULL == last_static_label->val) {
294 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
295 }
296 }
297
298 return CMT_DECODE_MSGPACK_SUCCESS;
299 }
300
unpack_metric_label(mpack_reader_t * reader,size_t index,void * context)301 static int unpack_metric_label(mpack_reader_t *reader, size_t index, void *context)
302 {
303 struct cmt_msgpack_decode_context *decode_context;
304
305 if (NULL == reader ||
306 NULL == context ) {
307 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
308 }
309
310 decode_context = (struct cmt_msgpack_decode_context *) context;
311
312 return unpack_label(reader,
313 index,
314 &decode_context->unique_label_list,
315 &decode_context->metric->labels);
316 }
317
unpack_metric_ts(mpack_reader_t * reader,size_t index,void * context)318 static int unpack_metric_ts(mpack_reader_t *reader, size_t index, void *context)
319 {
320 struct cmt_msgpack_decode_context *decode_context;
321
322 if (NULL == reader ||
323 NULL == context ) {
324 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
325 }
326
327 decode_context = (struct cmt_msgpack_decode_context *) context;
328
329 return cmt_mpack_consume_uint_tag(reader, &decode_context->metric->timestamp);
330 }
331
unpack_metric_value(mpack_reader_t * reader,size_t index,void * context)332 static int unpack_metric_value(mpack_reader_t *reader, size_t index, void *context)
333 {
334 double value;
335 int result;
336 struct cmt_msgpack_decode_context *decode_context;
337
338 if (NULL == reader ||
339 NULL == context ) {
340 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
341 }
342
343 decode_context = (struct cmt_msgpack_decode_context *) context;
344
345 result = cmt_mpack_consume_double_tag(reader, &value);
346
347 if(CMT_DECODE_MSGPACK_SUCCESS == result) {
348 decode_context->metric->val = cmt_math_d64_to_uint64(value);
349 }
350
351 return result;
352 }
353
unpack_metric_labels(mpack_reader_t * reader,size_t index,void * context)354 static int unpack_metric_labels(mpack_reader_t *reader, size_t index, void *context)
355 {
356 if (NULL == reader ||
357 NULL == context) {
358 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
359 }
360
361 return cmt_mpack_unpack_array(reader,
362 unpack_metric_label,
363 context);
364 }
365
unpack_metric(mpack_reader_t * reader,struct cmt_msgpack_decode_context * decode_context,struct cmt_metric ** out_metric)366 static int unpack_metric(mpack_reader_t *reader,
367 struct cmt_msgpack_decode_context *decode_context,
368 struct cmt_metric **out_metric)
369 {
370 int result;
371 struct cmt_metric *metric;
372 struct cmt_mpack_map_entry_callback_t callbacks[] = \
373 {
374 {"ts", unpack_metric_ts},
375 {"value", unpack_metric_value},
376 {"labels", unpack_metric_labels},
377 {NULL, NULL}
378 };
379
380 if (NULL == reader ||
381 NULL == decode_context ||
382 NULL == out_metric) {
383 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
384 }
385
386 /* Maybe we could move this cmt_metric constructor code to its own file, add a
387 * destructor and update map_metric_create and map_metric_destroy to use them right?
388 */
389
390 metric = calloc(1, sizeof(struct cmt_metric));
391
392 if (NULL == metric) {
393 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
394 }
395
396 mk_list_init(&metric->labels);
397
398 decode_context->metric = metric;
399
400 result = cmt_mpack_unpack_map(reader, callbacks, (void *) decode_context);
401
402 if (CMT_DECODE_MSGPACK_SUCCESS != result) {
403 destroy_label_list(&metric->labels);
404
405 free(metric);
406 }
407 else {
408 *out_metric = metric;
409 }
410
411 return result;
412 }
413
unpack_metric_array_entry(mpack_reader_t * reader,size_t index,void * context)414 static int unpack_metric_array_entry(mpack_reader_t *reader, size_t index, void *context)
415 {
416 int result;
417 struct cmt_metric *metric;
418 struct cmt_msgpack_decode_context *decode_context;
419
420 if (NULL == reader ||
421 NULL == context) {
422 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
423 }
424
425 decode_context = (struct cmt_msgpack_decode_context *) context;
426
427 metric = NULL;
428 result = unpack_metric(reader, decode_context, &metric);
429
430 if (CMT_DECODE_MSGPACK_SUCCESS == result) {
431 if (0 == mk_list_size(&metric->labels)) {
432 /* Should we care about finding more than one "implicitly static metric" in
433 * the array?
434 */
435
436 decode_context->map->metric_static_set = 1;
437
438 decode_context->map->metric.val = metric->val;
439 decode_context->map->metric.hash = metric->hash;
440 decode_context->map->metric.timestamp = metric->timestamp;
441
442 free(metric);
443 }
444 else
445 {
446 mk_list_add(&metric->_head, &decode_context->map->metrics);
447 }
448 }
449
450 return result;
451 }
452
unpack_meta_ver(mpack_reader_t * reader,size_t index,void * context)453 static int unpack_meta_ver(mpack_reader_t *reader, size_t index, void *context)
454 {
455 uint64_t value;
456 int result;
457
458 if (NULL == reader ||
459 NULL == context) {
460 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
461 }
462
463 result = cmt_mpack_consume_uint_tag(reader, &value);
464
465 if (CMT_DECODE_MSGPACK_SUCCESS == result) {
466 if (MSGPACK_ENCODER_VERSION != value) {
467 result = CMT_DECODE_MSGPACK_VERSION_ERROR;
468 }
469 }
470
471 return result;
472 }
473
unpack_meta_type(mpack_reader_t * reader,size_t index,void * context)474 static int unpack_meta_type(mpack_reader_t *reader, size_t index, void *context)
475 {
476 uint64_t value;
477 int result;
478 struct cmt_msgpack_decode_context *decode_context;
479
480 if (NULL == reader ||
481 NULL == context) {
482 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
483 }
484
485 decode_context = (struct cmt_msgpack_decode_context *) context;
486
487 result = cmt_mpack_consume_uint_tag(reader, &value);
488
489 if (CMT_DECODE_MSGPACK_SUCCESS == result) {
490 decode_context->map->type = value;
491 }
492
493 return result;
494 }
495
unpack_meta_opts(mpack_reader_t * reader,size_t index,void * context)496 static int unpack_meta_opts(mpack_reader_t *reader, size_t index, void *context)
497 {
498 struct cmt_msgpack_decode_context *decode_context;
499
500 if (NULL == reader ||
501 NULL == context) {
502 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
503 }
504
505 decode_context = (struct cmt_msgpack_decode_context *) context;
506
507 return unpack_opts(reader, decode_context->map->opts);
508 }
509
unpack_meta_label_dictionary(mpack_reader_t * reader,size_t index,void * context)510 static int unpack_meta_label_dictionary(mpack_reader_t *reader, size_t index, void *context)
511 {
512 struct cmt_msgpack_decode_context *decode_context;
513
514 if (NULL == reader ||
515 NULL == context) {
516 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
517 }
518
519 decode_context = (struct cmt_msgpack_decode_context *) context;
520
521 return cmt_mpack_unpack_array(reader, unpack_label_dictionary_entry,
522 (void *) &decode_context->unique_label_list);
523 }
524
unpack_header_static_label(mpack_reader_t * reader,size_t index,void * context)525 static int unpack_header_static_label(mpack_reader_t *reader, size_t index, void *context)
526 {
527 if (NULL == reader ||
528 NULL == context) {
529 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
530 }
531
532 return unpack_static_label(reader, index, context);
533 }
534
unpack_meta_label(mpack_reader_t * reader,size_t index,void * context)535 static int unpack_meta_label(mpack_reader_t *reader, size_t index, void *context)
536 {
537 struct cmt_msgpack_decode_context *decode_context;
538
539 if (NULL == reader ||
540 NULL == context) {
541 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
542 }
543
544 decode_context = (struct cmt_msgpack_decode_context *) context;
545
546 return unpack_label(reader, index,
547 &decode_context->unique_label_list,
548 &decode_context->map->label_keys);
549 }
550
unpack_meta_static_labels(mpack_reader_t * reader,size_t index,void * context)551 static int unpack_meta_static_labels(mpack_reader_t *reader, size_t index, void *context)
552 {
553 if (NULL == reader ||
554 NULL == context) {
555 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
556 }
557
558 return cmt_mpack_unpack_array(reader, unpack_header_static_label, context);
559 }
560
unpack_meta_labels(mpack_reader_t * reader,size_t index,void * context)561 static int unpack_meta_labels(mpack_reader_t *reader, size_t index, void *context)
562 {
563 if (NULL == reader ||
564 NULL == context) {
565 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
566 }
567
568 return cmt_mpack_unpack_array(reader, unpack_meta_label, context);
569 }
570
unpack_basic_type_meta(mpack_reader_t * reader,size_t index,void * context)571 static int unpack_basic_type_meta(mpack_reader_t *reader, size_t index, void *context)
572 {
573 int result;
574 struct cmt_msgpack_decode_context *decode_context;
575 struct cmt_mpack_map_entry_callback_t callbacks[] = \
576 {
577 {"ver", unpack_meta_ver},
578 {"type", unpack_meta_type},
579 {"opts", unpack_meta_opts},
580 {"label_dictionary", unpack_meta_label_dictionary},
581 {"static_labels", unpack_meta_static_labels},
582 {"labels", unpack_meta_labels},
583 {NULL, NULL}
584 };
585
586 if (NULL == reader ||
587 NULL == context) {
588 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
589 }
590
591 decode_context = (struct cmt_msgpack_decode_context *) context;
592
593 result = cmt_mpack_unpack_map(reader, callbacks, context);
594
595 if (CMT_DECODE_MSGPACK_SUCCESS == result) {
596 decode_context->map->label_count = mk_list_size(&decode_context->map->label_keys);
597 }
598
599 return result;
600 }
601
unpack_basic_type_values(mpack_reader_t * reader,size_t index,void * context)602 static int unpack_basic_type_values(mpack_reader_t *reader, size_t index, void *context)
603 {
604 if (NULL == reader ||
605 NULL == context) {
606 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
607 }
608
609 return cmt_mpack_unpack_array(reader,
610 unpack_metric_array_entry,
611 context);
612 }
613
unpack_basic_type(mpack_reader_t * reader,struct cmt * cmt,struct cmt_map ** map)614 static int unpack_basic_type(mpack_reader_t *reader, struct cmt *cmt, struct cmt_map **map)
615 {
616 int result;
617 struct cmt_msgpack_decode_context decode_context;
618 struct cmt_mpack_map_entry_callback_t callbacks[] = \
619 {
620 {"meta", unpack_basic_type_meta},
621 {"values", unpack_basic_type_values},
622 {NULL, NULL}
623 };
624
625 if (NULL == reader ||
626 NULL == map) {
627 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
628 }
629
630 *map = cmt_map_create(0, NULL, 0, NULL);
631
632 if (NULL == *map) {
633 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
634 }
635
636 (*map)->metric_static_set = 0;
637 (*map)->opts = calloc(1, sizeof(struct cmt_opts));
638
639 if (NULL == (*map)->opts) {
640 cmt_map_destroy(*map);
641
642 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
643 }
644
645 decode_context.cmt = cmt;
646 decode_context.map = *map;
647
648 if (mk_list_is_empty(&cmt->static_labels->list) == 0) {
649 decode_context.static_labels_unpacked = CMT_FALSE;
650 }
651 else {
652 decode_context.static_labels_unpacked = CMT_TRUE;
653 }
654
655 mk_list_init(&decode_context.unique_label_list);
656
657 result = cmt_mpack_unpack_map(reader, callbacks, (void *) &decode_context);
658
659 if (CMT_DECODE_MSGPACK_SUCCESS != result) {
660 cmt_map_destroy(*map);
661 free((*map)->opts);
662
663 *map = NULL;
664 }
665
666 destroy_label_list(&decode_context.unique_label_list);
667
668 return result;
669 }
670
append_unpacked_counter_to_metrics_context(struct cmt * context,struct cmt_map * map)671 static int append_unpacked_counter_to_metrics_context(struct cmt *context,
672 struct cmt_map *map)
673 {
674 struct cmt_counter *counter;
675
676 if (NULL == context ||
677 NULL == map ) {
678 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
679 }
680
681 counter = calloc(1, sizeof(struct cmt_counter));
682
683 if (NULL == counter) {
684 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
685 }
686
687 counter->map = map;
688
689 memcpy(&counter->opts, map->opts, sizeof(struct cmt_opts));
690
691 free(map->opts);
692
693 map->opts = &counter->opts;
694
695 mk_list_add(&counter->_head, &context->counters);
696
697 return CMT_DECODE_MSGPACK_SUCCESS;
698 }
699
append_unpacked_gauge_to_metrics_context(struct cmt * context,struct cmt_map * map)700 static int append_unpacked_gauge_to_metrics_context(struct cmt *context,
701 struct cmt_map *map)
702 {
703 struct cmt_gauge *gauge;
704
705 if (NULL == context ||
706 NULL == map ) {
707 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
708 }
709
710 gauge = calloc(1, sizeof(struct cmt_gauge));
711
712 if (NULL == gauge) {
713 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
714 }
715
716 gauge->map = map;
717
718 memcpy(&gauge->opts, map->opts, sizeof(struct cmt_opts));
719
720 free(map->opts);
721
722 map->opts = &gauge->opts;
723
724 mk_list_add(&gauge->_head, &context->gauges);
725
726 return CMT_DECODE_MSGPACK_SUCCESS;
727 }
728
append_unpacked_untyped_to_metrics_context(struct cmt * context,struct cmt_map * map)729 static int append_unpacked_untyped_to_metrics_context(struct cmt *context,
730 struct cmt_map *map)
731 {
732 struct cmt_untyped *untyped;
733
734 if (NULL == context ||
735 NULL == map ) {
736 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
737 }
738
739 untyped = calloc(1, sizeof(struct cmt_untyped));
740 if (NULL == untyped) {
741 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
742 }
743
744 untyped->map = map;
745
746 memcpy(&untyped->opts, map->opts, sizeof(struct cmt_opts));
747
748 free(map->opts);
749
750 map->opts = &untyped->opts;
751
752 mk_list_add(&untyped->_head, &context->untypeds);
753
754 return CMT_DECODE_MSGPACK_SUCCESS;
755 }
756
unpack_basic_type_entry(mpack_reader_t * reader,size_t index,void * context)757 static int unpack_basic_type_entry(mpack_reader_t *reader, size_t index, void *context)
758 {
759 int result;
760 struct cmt *cmt;
761 struct cmt_map *map;
762
763 if (NULL == reader ||
764 NULL == context) {
765 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
766 }
767
768 cmt = (struct cmt *) context;
769
770 result = unpack_basic_type(reader, cmt, &map);
771
772 if (CMT_DECODE_MSGPACK_SUCCESS == result) {
773 if (CMT_COUNTER == map->type) {
774 result = append_unpacked_counter_to_metrics_context(cmt, map);
775 }
776 else if (CMT_GAUGE == map->type) {
777 result = append_unpacked_gauge_to_metrics_context(cmt, map);
778 }
779 else if (CMT_HISTOGRAM == map->type) {
780 // result = append_unpacked_histogram_to_metrics_context(cmt, map);
781 }
782 else if (CMT_UNTYPED == map->type) {
783 result = append_unpacked_untyped_to_metrics_context(cmt, map);
784 }
785 }
786
787 return result;
788 }
789
unpack_basic_type_entries(mpack_reader_t * reader,struct cmt * cmt)790 static int unpack_basic_type_entries(mpack_reader_t *reader, struct cmt *cmt)
791 {
792 if (NULL == reader ||
793 NULL == cmt) {
794 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
795 }
796
797 return cmt_mpack_unpack_array(reader,
798 unpack_basic_type_entry,
799 (void *) cmt);
800 }
801
802 /* Convert cmetrics msgpack payload and generate a CMetrics context */
cmt_decode_msgpack_create(struct cmt ** out_cmt,char * in_buf,size_t in_size,size_t * offset)803 int cmt_decode_msgpack_create(struct cmt **out_cmt, char *in_buf, size_t in_size,
804 size_t *offset)
805 {
806 struct cmt *cmt;
807 mpack_reader_t reader;
808 int result;
809 size_t remainder;
810
811 if (NULL == out_cmt ||
812 NULL == in_buf ||
813 NULL == offset ||
814 in_size < *offset ) {
815 return CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR;
816 }
817
818 if (0 == in_size ||
819 0 == (in_size - *offset) ) {
820 return CMT_DECODE_MSGPACK_INSUFFICIENT_DATA;
821 }
822
823 cmt = cmt_create();
824
825 if (NULL == cmt) {
826 return CMT_DECODE_MSGPACK_ALLOCATION_ERROR;
827 }
828
829 in_size -= *offset;
830
831 mpack_reader_init_data(&reader, &in_buf[*offset], in_size);
832
833 result = unpack_basic_type_entries(&reader, cmt);
834
835 remainder = mpack_reader_remaining(&reader, NULL);
836
837 *offset += in_size - remainder;
838
839 result = mpack_reader_destroy(&reader);
840
841 if (CMT_DECODE_MSGPACK_SUCCESS != result) {
842 cmt_destroy(cmt);
843 }
844 else {
845 *out_cmt = cmt;
846 }
847
848 return result;
849 }
850
cmt_decode_msgpack_destroy(struct cmt * cmt)851 void cmt_decode_msgpack_destroy(struct cmt *cmt)
852 {
853 if (NULL != cmt) {
854 cmt_destroy(cmt);
855 }
856 }
857