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;
216
217 switch (value->type)
218 {
219 case ZBX_VARIANT_STR:
220 return SUCCEED;
221 case ZBX_VARIANT_DBL:
222 value_str = zbx_dsprintf(NULL, ZBX_FS_DBL, 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 ZBX_THREAD_LOCAL static char buffer[ZBX_MAX_UINT64_LEN + 1];
292 zbx_uint32_t size, i, len;
293
294 switch (value->type)
295 {
296 case ZBX_VARIANT_DBL:
297 zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_DBL, 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)352 int zbx_validate_value_dbl(double value)
353 {
354 /* field with precision 16, scale 4 [NUMERIC(16,4)] */
355 const double pg_min_numeric = -1e12;
356 const double pg_max_numeric = 1e12;
357
358 if (value <= pg_min_numeric || value >= pg_max_numeric)
359 return FAIL;
360
361 return SUCCEED;
362 }
363
364 /******************************************************************************
365 * *
366 * Function: variant_compare_empty *
367 * *
368 * Purpose: compares two variant values when at least one is empty (having *
369 * type of ZBX_VARIANT_NONE) *
370 * *
371 ******************************************************************************/
variant_compare_empty(const zbx_variant_t * value1,const zbx_variant_t * value2)372 static int variant_compare_empty(const zbx_variant_t *value1, const zbx_variant_t *value2)
373 {
374 if (ZBX_VARIANT_NONE == value1->type)
375 {
376 if (ZBX_VARIANT_NONE == value2->type)
377 return 0;
378
379 return -1;
380 }
381
382 return 1;
383 }
384
385 /******************************************************************************
386 * *
387 * Function: variant_compare_bin *
388 * *
389 * Purpose: compare two variant values when at least one contains binary data *
390 * *
391 ******************************************************************************/
variant_compare_bin(const zbx_variant_t * value1,const zbx_variant_t * value2)392 static int variant_compare_bin(const zbx_variant_t *value1, const zbx_variant_t *value2)
393 {
394 if (ZBX_VARIANT_BIN == value1->type)
395 {
396 zbx_uint32_t size1, size2;
397
398 if (ZBX_VARIANT_BIN != value2->type)
399 return 1;
400
401 memcpy(&size1, value1->data.bin, sizeof(size1));
402 memcpy(&size2, value2->data.bin, sizeof(size2));
403 ZBX_RETURN_IF_NOT_EQUAL(size1, size2);
404 return memcmp(value1->data.bin, value2->data.bin, size1 + sizeof(size1));
405 }
406
407 return -1;
408 }
409
410 /******************************************************************************
411 * *
412 * Function: variant_compare_str *
413 * *
414 * Purpose: compare two variant values when at least one is string *
415 * *
416 ******************************************************************************/
variant_compare_str(const zbx_variant_t * value1,const zbx_variant_t * value2)417 static int variant_compare_str(const zbx_variant_t *value1, const zbx_variant_t *value2)
418 {
419 if (ZBX_VARIANT_STR == value1->type)
420 return strcmp(value1->data.str, zbx_variant_value_desc(value2));
421
422 return strcmp(zbx_variant_value_desc(value1), value2->data.str);
423 }
424
425 /******************************************************************************
426 * *
427 * Function: variant_compare_dbl *
428 * *
429 * Purpose: compare two variant values when at least one is double and the *
430 * other is double, uint64 or a string representing a valid double *
431 * value *
432 * *
433 ******************************************************************************/
variant_compare_dbl(const zbx_variant_t * value1,const zbx_variant_t * value2)434 static int variant_compare_dbl(const zbx_variant_t *value1, const zbx_variant_t *value2)
435 {
436 double value1_dbl, value2_dbl;
437
438 switch (value1->type)
439 {
440 case ZBX_VARIANT_DBL:
441 value1_dbl = value1->data.dbl;
442 break;
443 case ZBX_VARIANT_UI64:
444 value1_dbl = value1->data.ui64;
445 break;
446 case ZBX_VARIANT_STR:
447 value1_dbl = atof(value1->data.str);
448 break;
449 default:
450 THIS_SHOULD_NEVER_HAPPEN;
451 exit(EXIT_FAILURE);
452 }
453
454 switch (value2->type)
455 {
456 case ZBX_VARIANT_DBL:
457 value2_dbl = value2->data.dbl;
458 break;
459 case ZBX_VARIANT_UI64:
460 value2_dbl = value2->data.ui64;
461 break;
462 case ZBX_VARIANT_STR:
463 value2_dbl = atof(value2->data.str);
464 break;
465 default:
466 THIS_SHOULD_NEVER_HAPPEN;
467 exit(EXIT_FAILURE);
468 }
469
470 if (SUCCEED == zbx_double_compare(value1_dbl, value2_dbl))
471 return 0;
472
473 ZBX_RETURN_IF_NOT_EQUAL(value1_dbl, value2_dbl);
474
475 THIS_SHOULD_NEVER_HAPPEN;
476 exit(EXIT_FAILURE);
477 }
478
479 /******************************************************************************
480 * *
481 * Function: variant_compare_ui64 *
482 * *
483 * Purpose: compare two variant values when both are uint64 *
484 * *
485 ******************************************************************************/
variant_compare_ui64(const zbx_variant_t * value1,const zbx_variant_t * value2)486 static int variant_compare_ui64(const zbx_variant_t *value1, const zbx_variant_t *value2)
487 {
488 ZBX_RETURN_IF_NOT_EQUAL(value1->data.ui64, value2->data.ui64);
489 return 0;
490 }
491
492 /******************************************************************************
493 * *
494 * Function: zbx_variant_compare *
495 * *
496 * Purpose: compare two variant values *
497 * *
498 * Parameters: value1 - [IN] the first value *
499 * value2 - [IN] the second value *
500 * *
501 * Return value: <0 - the first value is less than the second *
502 * >0 - the first value is greater than the second *
503 * 0 - the values are equal *
504 * *
505 * Comments: The following comparison logic is applied: *
506 * 1) value of 'none' type is always less than other types, two *
507 * 'none' types are equal *
508 * 2) value of binary type is always greater than other types, two *
509 * binary types are compared by length and then by contents *
510 * 3) if both values have uint64 types, they are compared as is *
511 * 4) if both values can be converted to floating point values the *
512 * conversion is done and the result is compared *
513 * 5) if any of value is of string type, the other is converted to *
514 * string and both are compared *
515 * *
516 ******************************************************************************/
zbx_variant_compare(const zbx_variant_t * value1,const zbx_variant_t * value2)517 int zbx_variant_compare(const zbx_variant_t *value1, const zbx_variant_t *value2)
518 {
519 if (ZBX_VARIANT_NONE == value1->type || ZBX_VARIANT_NONE == value2->type)
520 return variant_compare_empty(value1, value2);
521
522 if (ZBX_VARIANT_BIN == value1->type || ZBX_VARIANT_BIN == value2->type)
523 return variant_compare_bin(value1, value2);
524
525 if (ZBX_VARIANT_UI64 == value1->type && ZBX_VARIANT_UI64 == value2->type)
526 return variant_compare_ui64(value1, value2);
527
528 if ((ZBX_VARIANT_STR != value1->type || SUCCEED == is_double(value1->data.str, NULL)) &&
529 (ZBX_VARIANT_STR != value2->type || SUCCEED == is_double(value2->data.str, NULL)))
530 {
531 return variant_compare_dbl(value1, value2);
532 }
533
534 /* at this point at least one of the values is string data, other can be uint64, floating or string */
535 return variant_compare_str(value1, value2);
536 }
537