1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "zbxalgo.h"
22
zbx_variant_data_bin_copy(const void * bin)23 void *zbx_variant_data_bin_copy(const void *bin)
24 {
25 zbx_uint32_t size;
26 void *value_bin;
27
28 memcpy(&size, bin, sizeof(size));
29 value_bin = zbx_malloc(NULL, size + sizeof(size));
30 memcpy(value_bin, bin, size + sizeof(size));
31
32 return value_bin;
33 }
34
zbx_variant_data_bin_create(const void * data,zbx_uint32_t size)35 void *zbx_variant_data_bin_create(const void *data, zbx_uint32_t size)
36 {
37 void *value_bin;
38
39 value_bin = zbx_malloc(NULL, size + sizeof(size));
40 memcpy(value_bin, &size, sizeof(size));
41 memcpy((unsigned char *)value_bin + sizeof(size), data, size);
42
43 return value_bin;
44 }
45
zbx_variant_data_bin_get(const void * bin,void ** data)46 zbx_uint32_t zbx_variant_data_bin_get(const void *bin, void **data)
47 {
48 zbx_uint32_t size;
49
50 memcpy(&size, bin, sizeof(zbx_uint32_t));
51 if (NULL != data)
52 *data = ((unsigned char *)bin) + sizeof(size);
53 return size;
54 }
55
zbx_variant_clear(zbx_variant_t * value)56 void zbx_variant_clear(zbx_variant_t *value)
57 {
58 switch (value->type)
59 {
60 case ZBX_VARIANT_STR:
61 zbx_free(value->data.str);
62 break;
63 case ZBX_VARIANT_BIN:
64 zbx_free(value->data.bin);
65 break;
66 }
67
68 value->type = ZBX_VARIANT_NONE;
69 }
70
71 /******************************************************************************
72 * *
73 * Setter functions assign passed data and set corresponding variant *
74 * type. Note that for complex data it means the pointer is simply copied *
75 * instead of making a copy of the specified data. *
76 * *
77 * The contents of the destination value are not freed. When setting already *
78 * initialized variant it's safer to clear it beforehand, even if the variant *
79 * contains primitive value (numeric). *
80 * *
81 ******************************************************************************/
82
zbx_variant_set_str(zbx_variant_t * value,char * text)83 void zbx_variant_set_str(zbx_variant_t *value, char *text)
84 {
85 value->data.str = text;
86 value->type = ZBX_VARIANT_STR;
87 }
88
zbx_variant_set_dbl(zbx_variant_t * value,double value_dbl)89 void zbx_variant_set_dbl(zbx_variant_t *value, double value_dbl)
90 {
91 value->data.dbl = value_dbl;
92 value->type = ZBX_VARIANT_DBL;
93 }
94
zbx_variant_set_ui64(zbx_variant_t * value,zbx_uint64_t value_ui64)95 void zbx_variant_set_ui64(zbx_variant_t *value, zbx_uint64_t value_ui64)
96 {
97 value->data.ui64 = value_ui64;
98 value->type = ZBX_VARIANT_UI64;
99 }
100
zbx_variant_set_none(zbx_variant_t * value)101 void zbx_variant_set_none(zbx_variant_t *value)
102 {
103 value->type = ZBX_VARIANT_NONE;
104 }
105
zbx_variant_set_bin(zbx_variant_t * value,void * value_bin)106 void zbx_variant_set_bin(zbx_variant_t *value, void *value_bin)
107 {
108 value->data.bin = value_bin;
109 value->type = ZBX_VARIANT_BIN;
110 }
111
112 /******************************************************************************
113 * *
114 * Function: zbx_variant_copy *
115 * *
116 * Purpose: copy variant contents from source to value *
117 * *
118 * Comments: String and binary data are cloned, which is different from *
119 * setters where only the pointers are copied. *
120 * The contents of the destination value are not freed. If copied *
121 * over already initialized variant it's safer to clear it *
122 * beforehand. *
123 * *
124 ******************************************************************************/
zbx_variant_copy(zbx_variant_t * value,const zbx_variant_t * source)125 void zbx_variant_copy(zbx_variant_t *value, const zbx_variant_t *source)
126 {
127 switch (source->type)
128 {
129 case ZBX_VARIANT_STR:
130 zbx_variant_set_str(value, zbx_strdup(NULL, source->data.str));
131 break;
132 case ZBX_VARIANT_UI64:
133 zbx_variant_set_ui64(value, source->data.ui64);
134 break;
135 case ZBX_VARIANT_DBL:
136 zbx_variant_set_dbl(value, source->data.dbl);
137 break;
138 case ZBX_VARIANT_BIN:
139 zbx_variant_set_bin(value, zbx_variant_data_bin_copy(source->data.bin));
140 break;
141 case ZBX_VARIANT_NONE:
142 value->type = ZBX_VARIANT_NONE;
143 break;
144 }
145 }
146
variant_to_dbl(zbx_variant_t * value)147 static int variant_to_dbl(zbx_variant_t *value)
148 {
149 char buffer[MAX_STRING_LEN];
150 double value_dbl;
151
152 switch (value->type)
153 {
154 case ZBX_VARIANT_DBL:
155 return SUCCEED;
156 case ZBX_VARIANT_UI64:
157 zbx_variant_set_dbl(value, (double)value->data.ui64);
158 return SUCCEED;
159 case ZBX_VARIANT_STR:
160 zbx_strlcpy(buffer, value->data.str, sizeof(buffer));
161 break;
162 default:
163 return FAIL;
164 }
165
166 zbx_rtrim(buffer, "\n\r"); /* trim newline for historical reasons / backwards compatibility */
167 zbx_trim_float(buffer);
168
169 if (SUCCEED != is_double(buffer, &value_dbl))
170 return FAIL;
171
172 zbx_variant_clear(value);
173 zbx_variant_set_dbl(value, value_dbl);
174
175 return SUCCEED;
176 }
177
variant_to_ui64(zbx_variant_t * value)178 static int variant_to_ui64(zbx_variant_t *value)
179 {
180 zbx_uint64_t value_ui64;
181 char buffer[MAX_STRING_LEN];
182
183 switch (value->type)
184 {
185 case ZBX_VARIANT_UI64:
186 return SUCCEED;
187 case ZBX_VARIANT_DBL:
188 if (0 > value->data.dbl)
189 return FAIL;
190
191 zbx_variant_set_ui64(value, value->data.dbl);
192 return SUCCEED;
193 case ZBX_VARIANT_STR:
194 zbx_strlcpy(buffer, value->data.str, sizeof(buffer));
195 break;
196 default:
197 return FAIL;
198 }
199
200 zbx_rtrim(buffer, "\n\r"); /* trim newline for historical reasons / backwards compatibility */
201 zbx_trim_integer(buffer);
202 del_zeros(buffer);
203
204 if (SUCCEED != is_uint64(buffer, &value_ui64))
205 return FAIL;
206
207 zbx_variant_clear(value);
208 zbx_variant_set_ui64(value, value_ui64);
209
210 return SUCCEED;
211 }
212
variant_to_str(zbx_variant_t * value)213 static int variant_to_str(zbx_variant_t *value)
214 {
215 char *value_str, buffer[ZBX_MAX_DOUBLE_LEN + 1];
216
217 switch (value->type)
218 {
219 case ZBX_VARIANT_STR:
220 return SUCCEED;
221 case ZBX_VARIANT_DBL:
222 value_str = zbx_strdup(NULL, zbx_print_double(buffer, sizeof(buffer), value->data.dbl));
223 del_zeros(value_str);
224 break;
225 case ZBX_VARIANT_UI64:
226 value_str = zbx_dsprintf(NULL, ZBX_FS_UI64, value->data.ui64);
227 break;
228 default:
229 return FAIL;
230 }
231
232 zbx_variant_clear(value);
233 zbx_variant_set_str(value, value_str);
234
235 return SUCCEED;
236 }
237
zbx_variant_convert(zbx_variant_t * value,int type)238 int zbx_variant_convert(zbx_variant_t *value, int type)
239 {
240 switch(type)
241 {
242 case ZBX_VARIANT_UI64:
243 return variant_to_ui64(value);
244 case ZBX_VARIANT_DBL:
245 return variant_to_dbl(value);
246 case ZBX_VARIANT_STR:
247 return variant_to_str(value);
248 case ZBX_VARIANT_NONE:
249 zbx_variant_clear(value);
250 return SUCCEED;
251 default:
252 return FAIL;
253 }
254 }
255
zbx_variant_set_numeric(zbx_variant_t * value,const char * text)256 int zbx_variant_set_numeric(zbx_variant_t *value, const char *text)
257 {
258 zbx_uint64_t value_ui64;
259 double dbl_tmp;
260 char buffer[MAX_STRING_LEN];
261
262 zbx_strlcpy(buffer, text, sizeof(buffer));
263
264 zbx_rtrim(buffer, "\n\r"); /* trim newline for historical reasons / backwards compatibility */
265 zbx_trim_integer(buffer);
266 del_zeros(buffer);
267
268 if ('+' == buffer[0])
269 {
270 /* zbx_trim_integer() stripped one '+' sign, so there's more than one '+' sign in the 'text' argument */
271 return FAIL;
272 }
273
274 if (SUCCEED == is_uint64(buffer, &value_ui64))
275 {
276 zbx_variant_set_ui64(value, value_ui64);
277 return SUCCEED;
278 }
279
280 if (SUCCEED == is_double(buffer, &dbl_tmp))
281 {
282 zbx_variant_set_dbl(value, dbl_tmp);
283 return SUCCEED;
284 }
285
286 return FAIL;
287 }
288
zbx_variant_value_desc(const zbx_variant_t * value)289 const char *zbx_variant_value_desc(const zbx_variant_t *value)
290 {
291 static ZBX_THREAD_LOCAL char buffer[ZBX_MAX_DOUBLE_LEN + 1];
292 zbx_uint32_t size, i, len;
293
294 switch (value->type)
295 {
296 case ZBX_VARIANT_DBL:
297 zbx_print_double(buffer, sizeof(buffer), value->data.dbl);
298 del_zeros(buffer);
299 return buffer;
300 case ZBX_VARIANT_UI64:
301 zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_UI64, value->data.ui64);
302 return buffer;
303 case ZBX_VARIANT_STR:
304 return value->data.str;
305 case ZBX_VARIANT_NONE:
306 return "";
307 case ZBX_VARIANT_BIN:
308 memcpy(&size, value->data.bin, sizeof(size));
309 if (0 != (len = MIN(sizeof(buffer) / 3, size)))
310 {
311 const unsigned char *ptr = (const unsigned char *)value->data.bin + sizeof(size);
312
313 for (i = 0; i < len; i++)
314 zbx_snprintf(buffer + i * 3, sizeof(buffer) - i * 3, "%02x ", ptr[i]);
315
316 buffer[i * 3 - 1] = '\0';
317 }
318 else
319 buffer[0] = '\0';
320 return buffer;
321 default:
322 THIS_SHOULD_NEVER_HAPPEN;
323 return ZBX_UNKNOWN_STR;
324 }
325 }
326
zbx_get_variant_type_desc(unsigned char type)327 const char *zbx_get_variant_type_desc(unsigned char type)
328 {
329 switch (type)
330 {
331 case ZBX_VARIANT_DBL:
332 return "double";
333 case ZBX_VARIANT_UI64:
334 return "uint64";
335 case ZBX_VARIANT_STR:
336 return "string";
337 case ZBX_VARIANT_NONE:
338 return "none";
339 case ZBX_VARIANT_BIN:
340 return "binary";
341 default:
342 THIS_SHOULD_NEVER_HAPPEN;
343 return ZBX_UNKNOWN_STR;
344 }
345 }
346
zbx_variant_type_desc(const zbx_variant_t * value)347 const char *zbx_variant_type_desc(const zbx_variant_t *value)
348 {
349 return zbx_get_variant_type_desc(value->type);
350 }
351
zbx_validate_value_dbl(double value,int dbl_precision)352 int zbx_validate_value_dbl(double value, int dbl_precision)
353 {
354 if ((ZBX_DB_DBL_PRECISION_ENABLED == dbl_precision && (value < -1e+308 || value > 1e+308)) ||
355 (ZBX_DB_DBL_PRECISION_ENABLED != dbl_precision && (value <= -1e12 || value >= 1e12)))
356 {
357 return FAIL;
358 }
359
360 return SUCCEED;
361 }
362
363 /******************************************************************************
364 * *
365 * Function: variant_compare_empty *
366 * *
367 * Purpose: compares two variant values when at least one is empty (having *
368 * type of ZBX_VARIANT_NONE) *
369 * *
370 ******************************************************************************/
variant_compare_empty(const zbx_variant_t * value1,const zbx_variant_t * value2)371 static int variant_compare_empty(const zbx_variant_t *value1, const zbx_variant_t *value2)
372 {
373 if (ZBX_VARIANT_NONE == value1->type)
374 {
375 if (ZBX_VARIANT_NONE == value2->type)
376 return 0;
377
378 return -1;
379 }
380
381 return 1;
382 }
383
384 /******************************************************************************
385 * *
386 * Function: variant_compare_bin *
387 * *
388 * Purpose: compare two variant values when at least one contains binary data *
389 * *
390 ******************************************************************************/
variant_compare_bin(const zbx_variant_t * value1,const zbx_variant_t * value2)391 static int variant_compare_bin(const zbx_variant_t *value1, const zbx_variant_t *value2)
392 {
393 if (ZBX_VARIANT_BIN == value1->type)
394 {
395 zbx_uint32_t size1, size2;
396
397 if (ZBX_VARIANT_BIN != value2->type)
398 return 1;
399
400 memcpy(&size1, value1->data.bin, sizeof(size1));
401 memcpy(&size2, value2->data.bin, sizeof(size2));
402 ZBX_RETURN_IF_NOT_EQUAL(size1, size2);
403 return memcmp(value1->data.bin, value2->data.bin, size1 + sizeof(size1));
404 }
405
406 return -1;
407 }
408
409 /******************************************************************************
410 * *
411 * Function: variant_compare_str *
412 * *
413 * Purpose: compare two variant values when at least one is string *
414 * *
415 ******************************************************************************/
variant_compare_str(const zbx_variant_t * value1,const zbx_variant_t * value2)416 static int variant_compare_str(const zbx_variant_t *value1, const zbx_variant_t *value2)
417 {
418 if (ZBX_VARIANT_STR == value1->type)
419 return strcmp(value1->data.str, zbx_variant_value_desc(value2));
420
421 return strcmp(zbx_variant_value_desc(value1), value2->data.str);
422 }
423
424 /******************************************************************************
425 * *
426 * Function: variant_compare_dbl *
427 * *
428 * Purpose: compare two variant values when at least one is double and the *
429 * other is double, uint64 or a string representing a valid double *
430 * value *
431 * *
432 ******************************************************************************/
variant_compare_dbl(const zbx_variant_t * value1,const zbx_variant_t * value2)433 static int variant_compare_dbl(const zbx_variant_t *value1, const zbx_variant_t *value2)
434 {
435 double value1_dbl, value2_dbl;
436
437 switch (value1->type)
438 {
439 case ZBX_VARIANT_DBL:
440 value1_dbl = value1->data.dbl;
441 break;
442 case ZBX_VARIANT_UI64:
443 value1_dbl = value1->data.ui64;
444 break;
445 case ZBX_VARIANT_STR:
446 value1_dbl = atof(value1->data.str);
447 break;
448 default:
449 THIS_SHOULD_NEVER_HAPPEN;
450 exit(EXIT_FAILURE);
451 }
452
453 switch (value2->type)
454 {
455 case ZBX_VARIANT_DBL:
456 value2_dbl = value2->data.dbl;
457 break;
458 case ZBX_VARIANT_UI64:
459 value2_dbl = value2->data.ui64;
460 break;
461 case ZBX_VARIANT_STR:
462 value2_dbl = atof(value2->data.str);
463 break;
464 default:
465 THIS_SHOULD_NEVER_HAPPEN;
466 exit(EXIT_FAILURE);
467 }
468
469 if (SUCCEED == zbx_double_compare(value1_dbl, value2_dbl))
470 return 0;
471
472 ZBX_RETURN_IF_NOT_EQUAL(value1_dbl, value2_dbl);
473
474 THIS_SHOULD_NEVER_HAPPEN;
475 exit(EXIT_FAILURE);
476 }
477
478 /******************************************************************************
479 * *
480 * Function: variant_compare_ui64 *
481 * *
482 * Purpose: compare two variant values when both are uint64 *
483 * *
484 ******************************************************************************/
variant_compare_ui64(const zbx_variant_t * value1,const zbx_variant_t * value2)485 static int variant_compare_ui64(const zbx_variant_t *value1, const zbx_variant_t *value2)
486 {
487 ZBX_RETURN_IF_NOT_EQUAL(value1->data.ui64, value2->data.ui64);
488 return 0;
489 }
490
491 /******************************************************************************
492 * *
493 * Function: zbx_variant_compare *
494 * *
495 * Purpose: compare two variant values *
496 * *
497 * Parameters: value1 - [IN] the first value *
498 * value2 - [IN] the second value *
499 * *
500 * Return value: <0 - the first value is less than the second *
501 * >0 - the first value is greater than the second *
502 * 0 - the values are equal *
503 * *
504 * Comments: The following comparison logic is applied: *
505 * 1) value of 'none' type is always less than other types, two *
506 * 'none' types are equal *
507 * 2) value of binary type is always greater than other types, two *
508 * binary types are compared by length and then by contents *
509 * 3) if both values have uint64 types, they are compared as is *
510 * 4) if both values can be converted to floating point values the *
511 * conversion is done and the result is compared *
512 * 5) if any of value is of string type, the other is converted to *
513 * string and both are compared *
514 * *
515 ******************************************************************************/
zbx_variant_compare(const zbx_variant_t * value1,const zbx_variant_t * value2)516 int zbx_variant_compare(const zbx_variant_t *value1, const zbx_variant_t *value2)
517 {
518 if (ZBX_VARIANT_NONE == value1->type || ZBX_VARIANT_NONE == value2->type)
519 return variant_compare_empty(value1, value2);
520
521 if (ZBX_VARIANT_BIN == value1->type || ZBX_VARIANT_BIN == value2->type)
522 return variant_compare_bin(value1, value2);
523
524 if (ZBX_VARIANT_UI64 == value1->type && ZBX_VARIANT_UI64 == value2->type)
525 return variant_compare_ui64(value1, value2);
526
527 if ((ZBX_VARIANT_STR != value1->type || SUCCEED == is_double(value1->data.str, NULL)) &&
528 (ZBX_VARIANT_STR != value2->type || SUCCEED == is_double(value2->data.str, NULL)))
529 {
530 return variant_compare_dbl(value1, value2);
531 }
532
533 /* at this point at least one of the values is string data, other can be uint64, floating or string */
534 return variant_compare_str(value1, value2);
535 }
536