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