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